home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / utility / v11n02.zip / ZCOPY.ASM < prev    next >
Assembly Source File  |  1992-01-02  |  94KB  |  1,975 lines

  1.             PAGE 75,132
  2. ;----------------------------------------------------------------------
  3. ; ZCOPY - Transfer files via the COM port.  Syntax is
  4. ;----------------------------------------------------------------------
  5. CSEG        SEGMENT PARA PUBLIC 'CODE'
  6.             ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  7.             ORG     100H
  8. START:        JMP     BEGINNING            ; go to start of program
  9.             JMP     ZCXFER                ; transfer self
  10.  
  11.             DW      OFFSET CONFIG - $       ;configuration for pcremote
  12. COPYRIGHT   DB        "ZCOPY 1.4 (c) Copyright 1989, 1991 Ziff Communications Co."
  13.             DB        13,10,"PC Magazine ",254," Bob Flanders",13,10,"$",26
  14.                     ;version 1.4 modified by Terry Lahman and Kevin Sims to
  15.                     ;support PCREMOT2 version 1.0 and comm3/comm4.
  16. BIOS_DATA   EQU     40H                     ; bios data segment
  17. TIMER_LOW   EQU     WORD PTR 6CH            ; offset of low word
  18. TIMER_HI    EQU     WORD PTR 6EH            ; ... high word
  19. LSR        EQU     5                       ; lsr register offset
  20. LSR_DRDY    EQU     00000001B            ; data ready
  21. LSR_ORUN    EQU     00000010B            ; overrun error
  22. LSR_PRTY    EQU     00000100B            ; parity error
  23. LSR_FRM     EQU     00001000B            ; framing error
  24. LSR_BRK     EQU     00010000B            ; break interrupt
  25. LSR_THRE    EQU     00100000B            ; transmit holding reg empty
  26. LSR_TSRE    EQU     01000000B            ; transmit shift register emtpy
  27. LSR_ERR     EQU     LSR_FRM+LSR_PRTY+LSR_ORUN    ; error conditions
  28. LCR_SETUP   EQU     00000111B            ; set 8 bits, no parity, 2 stop
  29. LCR_DLAB    EQU     10000000B            ; divisor latch access bit
  30. MCR        EQU     4                ; mcr register offset
  31. MCR_DTR     EQU     00000001B            ; data terminal ready enable
  32. MCR_RTS     EQU     00000010B            ; request to send enable
  33. MCR_OUT2    EQU     00001000B            ; out2 control bit
  34. I8259        EQU     20H             ; 8259 control register addr
  35. EOI        EQU     20H             ; 8259 end of interrupt command
  36. I8259M        EQU     21H             ; 8259 mask register
  37. FLG        DB        0                ; system operation flag
  38. FLGR        EQU     80H             ;  receiver mode
  39. FLGO        EQU     40H             ;  /o overwrite
  40. FLGU        EQU     20H             ;  /u update
  41. FLGD        EQU     10H             ;  /d set current date
  42. FLGA        EQU     08H             ;  /a abort on full
  43. FLGP        EQU     04H             ;  /p pause for diskette
  44. FLGW        EQU     02H             ;  wait forever for other system
  45. FLGPCR      DB      0                       ;  PCREMOTE activated zcopy
  46. FLG_SET     EQU     07EH            ; flag mask on flg_set
  47. FLG1        DB        0                ; second flag
  48. FLG1I        EQU     80H             ;  system interrupts init'd
  49. FLG1O        EQU     40H             ;  output file is open
  50. FLG1B        EQU     20H             ;  break requested
  51. FLG1S        EQU     10H             ;  shutdown sent ok
  52. XBUF_LTS    DW        0                ; left to send
  53. XBUFL        EQU     4000H            ; buffer length
  54. XBUF_WL     EQU     XBUFL-WBUFL-1        ; write when over this value
  55. IO_LEN        EQU     512
  56. XBUF_RBL    EQU     (XBUFL/IO_LEN)*IO_LEN   ; number of bytes to read
  57. ERRORS        DW        8                ; errors so far
  58. MAX_ERRORS  EQU     3                ; max retries before resync
  59. SYNC_BYTE   EQU     08H             ; first byte to sync on
  60. SYNC_END    EQU     04H             ; end of sync bytes
  61. SYNC_LEN    EQU     128
  62. SYNC_INC    EQU     11
  63. CRC_VAL     EQU     01021H            ; value for CRC
  64. FNDOP        DB        4EH             ; find first/find next op
  65. ; Note:  ** ZCPARM requires PARM_TBL to be in "OUDAPW" order
  66. PARM_TBL    DB        'OUDAPW'               ; parameter specifications
  67. ARG1        DW        0                ; pointer to arg1
  68. ARG2        DW        0                ; pointer to arg2
  69. WAIT_COUNT  DW        0                ; timer tick counter
  70. TIME_COUNT  DW        0                ; timer inc amount
  71. COM_STR     DB        "COM"                   ; com definition
  72. BAUD_CNTR   DB        0                ; baud rate counter
  73. BAUD_TABLE  DB        1,'115k $',2,'57.6k$',3,'38.4k$',6,'19.2k$',12,'9600 $'
  74.         DB        24,'4800 $',48,'2400 $',96,'1200 $'
  75. LSR_VAL     DB        0                ; lsr value after interrupt
  76. LSR_NEW     DB        0                ; lsr value is new flag
  77. SEND_BLKNO  DW        0                ; next block number to send
  78. RCV_BLKNO   DW        0                ; next block to receive
  79. DFLDIR        DB        '.',0                   ; default receive directory
  80. CURDIR        DB        ".\"                    ; current directory
  81. FILENAME    DB        13 DUP (0)            ; work area for send filename
  82. ;-------message process table--------
  83. MSG_P_TBL:
  84. CRE_FILE    EQU     1                ; create requested file
  85. OPR_PROMPT  EQU     2                ; display a prompt
  86. SHUTDOWN    EQU     3                ; end the program
  87. MSG_ACK     EQU     4                ; previous message ok
  88. DATA_BLK    EQU     5                ; block of data
  89. EOF_MARK    EQU     6                ; end of file mark
  90. MSG_NAK     EQU     7                ; previous message not ok
  91. QRY_FLE     EQU     8                ; query file existence
  92. SET_FLG     EQU     9                ; set flag bits
  93. RESYNC        EQU     10                ; resync
  94. OPR_REPLY   EQU     11                ; reply from oper
  95. DIENOW        EQU     0FFH            ; die immediately
  96. DW OFFSET CRE_FILE_P,OFFSET ZCPPROMPT,OFFSET SHUTDOWN_P,OFFSET MSG_ACK_P
  97. DW OFFSET DATA_BLK_P,OFFSET EOF_MARK_P,OFFSET MSG_NAK_P,OFFSET QRY_FLE_P
  98. DW OFFSET SET_FLG_P,OFFSET RESYNC_P
  99. SOH        EQU     01H             ; start of header
  100. STX        EQU     02H             ; start of text
  101. ETX        EQU     03H             ; end of text
  102. ACK        EQU     06H             ; acknowledge
  103. NAK        EQU     15H             ; non-acknowledge
  104. RLR        EQU     1DH             ; request last response
  105. LAST_RESP   DB        NAK             ; last response holder
  106. SEC_30        EQU     (18*30)+(2*3)        ; 30 seconds in ticks
  107. SEC_10        EQU     (18*10)+(2*1)        ; 10 seconds in ticks
  108. SEC_5        EQU     (18*5)+1            ;  5 seconds in ticks
  109. SEC_3        EQU     (18*3)+1            ;  3 seconds in ticks
  110. SEC_1        EQU     (18*1)+1            ;  1 second  in ticks
  111. DSRWAIT     DW        SEC_30            ; tics to wait for dsr
  112. RETRIES     EQU     3                ; number of retries
  113. ;    message structure
  114. MSTX        EQU     0                ; start of message
  115. MCRC        EQU     MSTX+1            ; CRC value
  116. MLEN        EQU     MCRC+2            ; length of remainder less etx
  117. MBLKNO        EQU     MLEN+2            ; number of this block
  118. MCMD        EQU     MBLKNO+2            ; command
  119. MDATA        EQU     MCMD+1            ; data area
  120. ;                        ; etx address based on data len
  121. MOHEAD        EQU     6                ; overhead bytes not in len
  122. ;                        ;     stx + crc + len + etx
  123. ;    DTA structure for DOS "find matching" call
  124. DTA        EQU     80H             ; dta offset
  125. DTA_ATTR    EQU     BYTE PTR DTA+21        ; file attribute
  126. DTA_TIME    EQU     WORD PTR DTA_ATTR+1     ; file time
  127. DTA_DATE    EQU     WORD PTR DTA_TIME+2     ; file date
  128. DTA_LSIZ    EQU     WORD PTR DTA_DATE+2     ; file lsw of size
  129. DTA_HSIZ    EQU     WORD PTR DTA_LSIZ+2     ; file msw of size
  130. DTA_NAME    EQU     BYTE PTR DTA_HSIZ+2     ; file name of file
  131. DTA_LEN     EQU     DTA_NAME+15-DTA        ; length of dta find entry
  132. ;    messages to user
  133. PARMERR     DB     "Usage: ZCOPY source [target] [/w][/u][/o][/a][/p][/d][/#]"
  134.         DB        13,10
  135.         DB        "/w-wait",13,10
  136.         DB        "/u-newer files only",13,10
  137.         DB        "/o-overwrite",13,10
  138.         DB        "/a-abort if target full",13,10
  139.         DB        "/p-pause before copy",13,10
  140.         DB        "/d-use current date",13,10
  141.         DB        "/#-starting bps rate: /1 thru /6",13,10
  142.         DB        "   /1=115K,  /2=57.6K, /3=38.4K",13,10
  143.         DB        "   /4=19.2K, /5=9600,  /6=4800",13,10
  144.         DB      "   /7=2400, /8=1200",13,10,"$"
  145. BADDIR        DB        "Invalid directory.",13,10,'$'
  146. FILERR        DB        "No files specified.",13,10,'$'
  147. FILENOPEN   DB        "Unable to create, skipping.",13,10,'$'
  148. INVFIL        DB        "Invalid filename.",13,10,'$'
  149. DISKFULL    DB        "Disk full .. press a key ..",13,10,'$'
  150. BSENT        DB        " being sent.",13,10,'$'
  151. BRECVD        DB        " being received.",13,10,'$'
  152. TOOMANY     DB        "Resyncing ...      ",13,10,'$'
  153. FILEXISTS   DB        ": exists. Overwrite?",13,10,'$'
  154. TOOBIG        DB        ": won't fit, skipped.", 13, 10, '$'
  155. WAITING     DB        "Press a key to continue ..",13,10,'$'
  156. SHUTDOWN_R1 DB        13,10
  157. SHUTDOWN_R  DB        "ZCOPY is done."
  158. CRLF        DB        13,10,'$'
  159. TRYING        DB        13,"Baud rate $"
  160. SPDERROR    DB        13,10,"Link not established.",13,10,'$'
  161. SPDSET        DB        13,10,"Link established.",13,10,'$'
  162. NOTUP        DB        13,10,"Other node not detected.",13,10,'$'
  163.         DB        '.....'
  164. B_LEFT        DB        '.h blocks left.     ',13,'$'
  165. CONFIG:             ; used by PCREMOTE to reconfigure comm3/4 if necessary
  166. COMM_PORT3  DW      02E8H  ; comm port 3 address used by pcremote
  167. COMM_PORT4  DW      02E0H  ; comm port 4 address used by pcremote
  168. COMM3_INT   DB      4      ; interrupt used by comm 3
  169. COMM4_INT   DB      3      ; interrupt used by comm 4
  170.  
  171. BEGINNING   PROC    NEAR            ; start of program
  172.         MOV     DX,OFFSET COPYRIGHT
  173.         MOV     AH,9
  174.         INT     21H
  175.         MOV     BX, OFFSET BUF_START    ; bx -> start of buffer space
  176.         MOV     RBUF, BX            ; set offset of the receive buffer
  177.         MOV     RBUF_RPTR, BX        ; .. for receive
  178.         MOV     RBUF_GPTR, BX        ; .. and get
  179.         ADD     BX, RBUFL            ; bx -> start of send buffer
  180.         MOV     RBUF_HI, BX         ; .. save for int handler
  181.         MOV     SBUF, BX            ; set offset of the send buffer
  182.         ADD     BX, SBUFL            ; bx -> start of work buffer
  183.         MOV     WBUF, BX            ; set offset of the work buffer
  184.         ADD     BX, WBUFL            ; bx -> star to file build buffer
  185.         MOV     XBUF, BX            ; set pointer to buffer
  186.         MOV     XBUF_PTR, BX        ; .. and write pointer
  187.         ADD     BX, XBUFL            ; bx -> entry directory area
  188.         MOV     EDIR, BX            ; .. save pointer
  189.         MOV     AH, 19H            ; ah = get current drive
  190.         INT     21H             ; al = current drive
  191.         MOV     EDRV, AL            ; save entry drive
  192.         MOV     SI, EDIR            ; si -> current directory area
  193.         MOV     BYTE PTR [SI], '\'      ; .. start with backslash
  194.         INC     SI                ; si -> next byte
  195.         XOR     DL, DL            ; dl = default drive
  196.         MOV     AH, 47H            ; ah = get current dir
  197.         INT     21H             ; .. save in area
  198.         CALL    ZCPARM            ; set up parameters
  199.         CALL    ZCINIT            ; init interrupts
  200.         CALL    ZCSPEED            ; setup transfer speed
  201.         TEST    FLG, FLGR            ; Q. receiver?
  202.         JNZ     MAINRCV            ; A. yes .. rcv
  203.         MOV     AL, SET_FLG         ; al = set flags command
  204.         MOV     SI, OFFSET FLG        ; si -> flags byte
  205.         MOV     CX, 1            ; .. len to send
  206.         CALL    ZCBLKSND            ; .. send set flags
  207.         MOV     BX, WAIT_COUNT        ; bx = wait_count
  208.         ADD     BX, SEC_10            ; .. max 10 secs
  209. MAIN10:     CALL    ZCTRYRCV            ; Q. block available?
  210.         JNC     MAIN15            ; A. yes .. continue
  211.         CMP     WAIT_COUNT, BX        ; Q. timeout?
  212.         JB        MAIN10            ; A. no .. continue
  213.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  214.         CALL    ZCDIE            ; .. die of old age
  215. MAIN15:     OR        FLG, AL            ; save flags
  216.         TEST    FLG, FLGP            ; Q. pause before starting?
  217.         JZ        MAIN20            ; A. no .. wait
  218.         MOV     DI, OFFSET WAITING        ; di -> waiting prompt
  219.         CALL    ZCSPROMPT            ; .. wait for response
  220. MAIN20:     JMP     ZCSF            ; send the files requested
  221. MAINRCV:    CALL    ZCRECV            ; start receive mode
  222.         JMP     MAINRCV            ; .. continuously
  223. BEGINNING   ENDP
  224. ; ---------------------------------------------------------------------
  225. ;    This routine initializes the system interrupts.
  226. ; ---------------------------------------------------------------------
  227. ZCINIT        PROC    NEAR
  228.             MOV     DX, IO_BASE         ; dx = base io port
  229.         IN        AL, DX            ; .. clear any character
  230.         INC     DX                ; dx = ier
  231.         XOR     AL, AL            ; al = zero
  232.         OUT     DX, AL            ; no ints for now
  233.         ADD     DX, 3            ; dx = mcr
  234.         MOV     AL, MCR_DTR+MCR_RTS        ; set DTR and RTS on
  235.         OUT     DX, AL            ; .. set off all other stats
  236.         ADD     DX, 2            ; dx = msr
  237.         IN        AL, DX            ; .. reset msr now
  238.         MOV     AL, INT_VECTOR        ; al = com interupt to set
  239.         ADD     AL, 8            ; .. set to actual interrupt
  240.         MOV     SI, OFFSET OLD_COM        ; si -> save area for old
  241.         MOV     DX, OFFSET ZCINT        ; dx -> com int routine
  242.         CALL    ZCSETINT            ; set up the interrupt
  243.             MOV     AL, 08H            ; al = timer interrupt to set
  244.         MOV     SI, OFFSET OLD_TIMER    ; si -> save area for old
  245.         MOV     DX, OFFSET ZCTIMER        ; dx -> timer int routine
  246.         CALL    ZCSETINT            ; set up the interrupt
  247.         MOV     AL, 1BH            ; al = control break interrupt
  248.         MOV     SI, OFFSET OLD_CTLBRK   ; si -> save area for old
  249.         MOV     DX, OFFSET ZCCTLBRK     ; dx -> timer int routine
  250.         CALL    ZCSETINT            ; set up the interrupt
  251.         MOV     AL, 23H            ; al = control break interrupt
  252.         MOV     SI, OFFSET OLD_DOSCTLB  ; si -> save area for old
  253.         MOV     DX, OFFSET ZCCTLBRK     ; dx -> timer int routine
  254.         CALL    ZCSETINT            ; set up the interrupt
  255.         MOV     AL, 24H            ; ax = doserr interrupt to set
  256.         MOV     SI, OFFSET OLD_DOSERR   ; si -> save area for old
  257.         MOV     DX, OFFSET ZCDOSERR     ; dx -> dos error routine
  258.         CALL    ZCSETINT            ; set up the interrupt
  259.         MOV     DX, IO_BASE         ; dx -> base of com port
  260.         ADD     DX, 2            ; dx -> Int id register
  261.         MOV     ZCINTIIR1, DX        ; modify int rtn instruction
  262.         MOV     ZCINTIIR2, DX        ; modify int rtn instruction
  263.         INC     DX                ; dx -> line control reg
  264.         MOV     AL, LCR_SETUP        ; al = com parm setup
  265.         OUT     DX, AL            ; .. set line characteristics
  266.         INC     DX                ; dx -> modem control reg
  267.         MOV     AL, MCR_DTR+MCR_RTS+MCR_OUT2 ; al = set DTR, RTS, &OUT2
  268.         OUT     DX, AL            ; .. set MCR value
  269.         SUB     DX, 3            ; dx -> interrupt enable reg
  270.         MOV     AL, 05H            ; al = allow lsr & rx ints
  271.         OUT     DX, AL            ; .. set int enable register
  272.         IN        AL, 21H            ; al = current int mask
  273.         MOV     CL, INT_VECTOR        ; cl = interrupt to use
  274.         MOV     AH, 1            ; ah = 1 ..
  275.         SHL     AH, CL            ; .. shift bit to mask pos
  276.         NOT     AH                ; .. and invert mask
  277.         AND     AL, AH            ; .. set off mask bit
  278.         OUT     21H, AL            ; .. allow com interrupts
  279.         OR        FLG1, FLG1I         ; show initialized
  280.         MOV     AL, INT_VECTOR        ; al = int vector
  281.         DEC     AL                ; al -> lower vector
  282.         OR        AL, 0C0H            ; al = set 8259 priority cmd
  283.         OUT     20H, AL            ; .. reset priority
  284.         RET                 ; .. return to caller
  285. ZCINIT        ENDP
  286. ; ---------------------------------------------------------------------
  287. ;    This routine resets the system to pre-runtime settings.
  288. ; ---------------------------------------------------------------------
  289. ZCRESET     PROC    NEAR
  290.             MOV     AL, 0C7H            ; al = set priority command
  291.         OUT     20H, AL            ; reset normal 8259 priority
  292.         TEST    FLG1, FLG1O         ; Q. file open?
  293.         JZ        ZCRESET10            ; A. no .. continue
  294.         MOV     BX, HANDLE            ; bx = file handle
  295.         MOV     AH, 3EH            ; ah = close
  296.         INT     21H             ; .. close that file
  297. ZCRESET10:  MOV     CL, INT_VECTOR        ; cl = interrupt to use
  298.         IN        AL, 21H            ; al = current int mask
  299.         MOV     AH, 1            ; ah = 1 ..
  300.         SHL     AH, CL            ; .. shift bit to mask pos
  301.         OR        AL, AH            ; .. set on mask bit
  302.         OUT     21H, AL            ; .. disallow com interrupts
  303.         MOV     DX, IO_BASE         ; dx -> base of com port
  304.         INC     DX                ; dx -> interrupt enable reg
  305.         XOR     AL, AL            ; al = all interrupts off
  306.         OUT     DX, AL            ; .. disallow all interrupts
  307.         ADD     DX, 3            ; dx -> modem control reg
  308.         MOV     AL, MCR_DTR+MCR_RTS        ; leave DTR and RTS on and
  309.         OUT     DX, AL            ; .. set OUT2 off
  310.         MOV     AL, INT_VECTOR        ; al = com interupt to reset
  311.         ADD     AL, 8            ; .. set to actual interrupt
  312.         MOV     SI, OFFSET OLD_COM        ; si -> save area for old
  313.         CALL    ZCRESINT            ; reset the interrupt
  314.         MOV     AL, 1BH            ; al = ctlbreak interrupt
  315.         MOV     SI, OFFSET OLD_CTLBRK   ; si -> save area for old
  316.         CALL    ZCRESINT            ; reset the interrupt
  317.         MOV     AL, 23H            ; al = ctlbreak interrupt
  318.         MOV     SI, OFFSET OLD_DOSCTLB  ; si -> save area for old
  319.         CALL    ZCRESINT            ; reset the interrupt
  320.         MOV     AL, 08H            ; al = timer interrupt to reset
  321.         MOV     SI, OFFSET OLD_TIMER    ; si -> save area for old
  322.         CALL    ZCRESINT            ; reset the interrupt
  323.         CALL    ZCTIMUP            ; assure timer fully reset
  324.         MOV     AL, 24H            ; ax = doserr interrupt to reset
  325.         MOV     SI, OFFSET OLD_DOSERR   ; si -> save area for old
  326.         CALL    ZCRESINT            ; reset the interrupt
  327.         MOV     AH, 0EH            ; ah = DOS setdrive
  328.         MOV     DL, EDRV            ; dl = drive to set
  329.         INT     21H             ; reset original drive
  330.         MOV     AH, 3BH            ; ah = DOS set directory
  331.         MOV     DX, EDIR            ; dx -> original directory
  332.         INT     21H             ; reset original directory
  333.         RET                 ; .. return to caller
  334. ZCRESET     ENDP
  335. ; ---------------------------------------------------------------------
  336. ; This routine initializes an interrupt vector.
  337. ; Entry:al = interrupt to setup,si -> save area for old,dx -> routine to call
  338. ; ---------------------------------------------------------------------
  339. ZCSETINT    PROC    NEAR
  340.         PUSH    BX                ; save caller's bx
  341.         PUSH    ES                ; .. and es
  342.         MOV     AH, 35H            ; ah = get int vector
  343.         INT     21H             ; es:bx -> current vector
  344.         MOV     WORD PTR [SI], BX        ; save offset
  345.         MOV     WORD PTR [SI+2], ES     ; .. and segment
  346.         MOV     AH, 25H            ; ah = set int vector
  347.         INT     21H             ; .. set up the interrupt
  348.         POP     ES                ; restore regs
  349.         POP     BX
  350.         RET                 ; .. return to caller
  351. ZCSETINT    ENDP
  352. ; ---------------------------------------------------------------------
  353. ; This routine restores the original interrupt vector.
  354. ; Entry:al = interrupt to setup,si -> save area for old
  355. ; ---------------------------------------------------------------------
  356. ZCRESINT    PROC    NEAR
  357.         PUSH    DS                ; save ds
  358.         PUSH    DX                ; .. and dx
  359.         LDS     DX, [SI]            ; ds:dx -> original vector
  360.         MOV     AH, 25H            ; ah = set int vector
  361.         INT     21H             ; .. set up the interrupt
  362.         POP     DX                ; restore regs
  363.         POP     DS
  364.         RET                 ; .. return to caller
  365. ZCRESINT    ENDP
  366. ; ---------------------------------------------------------------------
  367. ; This routine intercepts control-breaks and handles them gracefully.
  368. ; ---------------------------------------------------------------------
  369. ZCCTLBRK    PROC    NEAR
  370.         OR        CS:FLG1, FLG1B        ; show break issued
  371.         IRET                ; return to caller
  372. ZCCTLBRK    ENDP
  373. ; ---------------------------------------------------------------------
  374. ; This routine increments a local timer variable when called.
  375. ; ---------------------------------------------------------------------
  376. ZCTIMER     PROC    NEAR
  377.         STI                 ; allow ints
  378.         PUSH    AX                ; save ax
  379.         MOV     AL, 20H            ; al = reset interrupt
  380.         OUT     20H, AL            ; .. reset it
  381.         POP     AX                ; restore ax
  382.         INC     CS:WAIT_COUNT        ; increment # ticks
  383.         INC     CS:TIME_COUNT        ; .. and timer ticks
  384.         IRET                ; return from interrupt
  385. ZCTIMER     ENDP
  386. ; ---------------------------------------------------------------------
  387. ; This routine updates the system timer.
  388. ; ---------------------------------------------------------------------
  389. ZCTIMUP     PROC    NEAR
  390.         OR        TIME_COUNT, 0        ; Q. any update?
  391.         JZ        ZCTIMUP90            ; A. no .. return
  392.         PUSH    DS                ; save ds
  393.         MOV     AX, 40H            ; ax -> bios low memory seg
  394.         MOV     DS, AX            ; ds -> bios low memory seg
  395.         XOR     AX, AX            ; ax = zero
  396.         XCHG    AX, CS:TIME_COUNT        ; ax = ticks since update
  397.         ADD     DS:[TIMER_LOW], AX        ; .. add to timer value
  398.         ADC     DS:[TIMER_HI], 0        ; .. and the overflow
  399.         POP     DS                ; restore ds
  400. ZCTIMUP90:  RET
  401. ZCTIMUP     ENDP
  402. ; ---------------------------------------------------------------------
  403. ; This routine intercepts and handles DOS critical errors.
  404. ; Entry: Standard INT 24h entry; Exit: Only allows retries and aborts.
  405. ; ---------------------------------------------------------------------
  406. ZCDOSERR    PROC    NEAR
  407.         PUSHF                ; save the flags
  408.         AND     AH, NOT 28H         ; allow retry, abort only
  409.         CALL    CS:OLD_DOSERR        ; .. call old routine
  410.         CMP     AL, 1            ; Q. retry?
  411.         JE        ZCDOSERR90            ; A. yes .. continue
  412.         OR        CS:FLG1, FLG1B        ; turn on die flag
  413.         MOV     AL, 0            ; .. and ignore error
  414. ZCDOSERR90: IRET
  415. ZCDOSERR    ENDP
  416. ; ---------------------------------------------------------------------
  417. ; Communications interrupt handler. Handled from the com port
  418. ;    specified by the user on the command line.
  419. ; ---------------------------------------------------------------------
  420. ZCINT        PROC    NEAR            ; interrupt handler entry point
  421.         PUSH    AX                ; save entry registers
  422.         PUSH    BX                ; ...
  423.         PUSH    DX                ;     ...
  424.         MOV     AL, EOI            ; al = EOI instruction
  425.         OUT     I8259, AL            ; .. reset the 8259
  426. ZCINT05:    MOV     DX, 0FFFFH            ; dx = int ID register addr
  427. ZCINTIIR1   EQU     WORD PTR ZCINT05+1        ; .. address to mod for iir
  428.         IN        AL, DX            ; al = int id
  429.         JMP     SHORT ZCINT17        ; .. process interrupt
  430. ZCINT10:    MOV     DX, 0FFFFH            ; dx = int ID register addr
  431. ZCINTIIR2   EQU     WORD PTR ZCINT10+1        ; .. address to mod for iir
  432. ZCINT15:    IN        AL, DX            ; al = interrupt ID
  433.         TEST    AL, 00000001B        ; Q. any interrupt?
  434.         JNZ     ZCINT90            ; A. no .. exit now.
  435. ZCINT17:    CMP     AL, 4            ; Q. received data int?
  436.         JNE     ZCINT50            ; A. no .. process stat regs
  437.         SUB     DX, 2            ; dx = base reg
  438.         IN        AL, DX            ; al = next receive character
  439. ZCINT_RPTR: MOV     BX, 0F1F2H            ; bx -> receive buffer
  440.         MOV     CS:[BX], AL         ; .. save received character
  441.         INC     BX                ; bx -> next receive char pos
  442. ZCINT_RHI:  CMP     BX, 0F1F2H            ; Q. end of receive buffer?
  443.         JNB     ZCINT_RBUF            ; A. yes .. set to rbuf
  444. ZCINT20:    MOV     CS:RBUF_RPTR, BX        ; save receive pointer
  445.         JMP     ZCINT10            ; see if another int occurred
  446. ZCINT_RBUF: MOV     BX, 0F1F2H            ; bx -> start of buffer
  447.         JMP     ZCINT20            ; .. and continue
  448. ZCINT50:    ADD     DX, 3            ; dx -> lsr
  449.         IN        AL, DX            ; .. get value
  450.         MOV     CS:LSR_VAL, AL        ; save lsr value
  451.         MOV     CS:LSR_NEW, 0FFH        ; .. show value is new
  452.         SUB     DX, 3            ; dx -> int ID reg
  453.         JMP     ZCINT15            ; See if done
  454. ZCINT90:    STI                 ; allow interrupt
  455.         POP     DX                ; Restore entry registers
  456.         POP     BX                ;     ...
  457.         POP     AX                ;      ...
  458.         IRET                ; return from interrupt
  459. RBUF_RPTR   EQU     WORD PTR ZCINT_RPTR+1   ; rptr word
  460. RBUF        EQU     WORD PTR ZCINT_RBUF+1   ; rbuf word
  461. RBUF_HI     EQU     WORD PTR ZCINT_RHI+2    ; hi word
  462. ZCINT        ENDP
  463. ; ---------------------------------------------------------------------
  464. ; This routine sends the requested character.
  465. ; Entry: al = character to send
  466. ; ---------------------------------------------------------------------
  467. ZCPUTC        PROC    NEAR
  468.         PUSH    BX                ; save registers
  469.         PUSH    CX
  470.         PUSH    DX
  471.         PUSH    SI
  472.         PUSH    AX
  473.         MOV     DX, IO_BASE         ; dx -> base io address
  474.         ADD     DX, LSR            ; dx = line status addr
  475. ZCPUTC10:   IN        AL, DX            ; al = lsr
  476.         AND     AL, LSR_THRE        ; leave tsre & thre on
  477.         CMP     AL, LSR_THRE        ; Q. all empty?
  478.         JNE     ZCPUTC10            ; A. no .. retry
  479.         POP     AX                ; get character
  480.         MOV     DX, IO_BASE         ; .. and base register
  481.         OUT     DX, AL            ; .. put the char
  482.         POP     SI                ; restore registers
  483.         POP     DX
  484.         POP     CX
  485.         POP     BX
  486.         RET                 ; ..and return to caller
  487. ZCPUTC        ENDP
  488. ; ---------------------------------------------------------------------
  489. ; This routine gets a character from the receive buffer if one is available.
  490. ; Exit: al = character; carry flag set indicates no character available
  491. ; ---------------------------------------------------------------------
  492. ZCGETC        PROC    NEAR            ; get a received char, if any
  493.         CALL    ZCCLA            ; Q. anything to get?
  494.         JNC     ZCGETC80            ; A. yes .. update pointers
  495.         RET                 ; .. else .. return to caller
  496. ZCGETC80:   PUSH    BX                ; save caller's bx
  497.         MOV     BX, RBUF_GPTR        ; bx = next get pointer
  498.         INC     BX                ; bx -> next position
  499.         CMP     BX, RBUF_HI         ; Q. end of buffer?
  500.         JB        ZCGETC90            ; A. no .. store as it
  501.         MOV     BX, RBUF            ; bx -> start of buffer
  502. ZCGETC90:   MOV     RBUF_GPTR, BX        ; save get pointer
  503.         POP     BX                ; restore caller's bx
  504.         CLC                 ; .. show char available
  505.         RET                 ; return to caller
  506. ZCGETC        ENDP
  507. ; ---------------------------------------------------------------------
  508. ; This routine reads one character from the receive buffer
  509. ; without adjusting the read buffer pointers.
  510. ; Exit: al = character; carry flag set indicates no character available
  511. ; ---------------------------------------------------------------------
  512. ZCCLA        PROC    NEAR
  513.         PUSH    BX                ; save registers
  514.         MOV     BX, RBUF_GPTR        ; bx = next get offset
  515.         CMP     BX, RBUF_RPTR        ; Q. anything to get?
  516.         JNE     ZCCLA10            ; A. yes .. continue
  517.         STC                 ; show no char found
  518.         JMP     SHORT ZCCLA90        ; .. and return to caller
  519. ZCCLA10:    MOV     AL, [BX]            ; al = char
  520.         CLC                 ; .. set carry to char found
  521. ZCCLA90:    POP     BX                ; restore registers
  522.         RET                 ; .. and return to caller
  523. ZCCLA        ENDP
  524. ; ---------------------------------------------------------------------
  525. ; This routine parses the command line.
  526. ; Exit: Returns to DOS if error else argument bits and values are set.
  527. ; ---------------------------------------------------------------------
  528. ZCPARM        PROC    NEAR
  529.         CALL    ZCUC            ; upper case the parm area
  530.         MOV     SI, 81H            ; si -> parms area
  531. ZCPARM10:   CALL    ZCPARMC            ; get parameter character
  532.         CMP     AL, '/'                 ; Q. option?
  533.         JE        ZCPARM80            ; A. yes .. check option
  534.         CMP     AL, 13            ; Q. end of line?
  535.         JE        ZCPARM50            ; A. yes .. exit
  536.         CMP     AL, ' '                 ; Q. blank?
  537.         JNA     ZCPARM10            ; A. yes .. skip
  538.         CALL    ZCARG            ; set the argument
  539.         JC        ZCPARMERR            ; .. die on an error
  540. ZCPARM30:   CALL    ZCPARMC            ; get next character
  541.         CMP     AL, 13            ; Q. end of line?
  542.         JE        ZCPARM50            ; A. yes .. process
  543.         CMP     AL, '/'                 ; Q. start of option?
  544.         JE        ZCPARM80            ; A. yes .. process
  545.         CMP     AL, ' '                 ; Q. end of parm?
  546.         JA        ZCPARM30            ; A. no .. next char
  547.         MOV     BYTE PTR [SI-1], 0        ; end the parm
  548.         JMP     ZCPARM10            ; .. look for next
  549. ZCPARM50:   MOV     BYTE PTR [SI-1], 0        ; zero out the <cr>
  550.         CMP     ARG1, 0            ; Q. parm 1 available?
  551.         JE        ZCPARMERR            ; A. no .. error
  552.         CMP     ARG2, 0            ; Q. Parm 2 available?
  553.         JNE     ZCPARM60            ; A. yes .. continue
  554.         MOV     ARG2, OFFSET DFLDIR     ; set up for current directory
  555. ZCPARM60:   CALL    ZCCOM            ; check the com parameter
  556.         CALL    ZCFLSET            ; set up file parameters
  557.         RET                 ; return to caller
  558. ZCPARM80:   MOV     BYTE PTR [SI-1], 0        ; end the parm
  559.         CALL    ZCPARMC            ; al = option character
  560.         CMP     AL, '1'                 ; Q. < 1?
  561.         JB        ZCPARM82            ; A. yes .. continue
  562.         CMP     AL, '8'            ; Greater than 8 ?
  563.         JA        ZCPARM82            ; A. yes .. continue
  564.         SUB     AL, '1'                 ; .. adjust the value
  565.         MOV     BAUD_CNTR, AL        ; .. save as starting baud
  566.         JMP     ZCPARM10            ; .. continue
  567. ZCPARM82:   LEA     DI, PARM_TBL        ; di -> table to search
  568.         MOV     CX, 6            ; cx = max entries
  569.      REPNE  SCASB                ; Q. entry found?
  570.         JNE     ZCPARM85            ; A. no .. check for /r option
  571.         MOV     AL, 2            ; al = "W" flag
  572.         SHL     AL, CL            ; .. do it
  573.         OR        FLG, AL            ; .. or in the flag
  574.         JMP     ZCPARM10            ; .. continue scanning
  575. ZCPARM85:   CMP     AL, 'R'                 ; Q. pcremote flag
  576.             JNE     ZCPARMERR               ; A. no .. parameter in error
  577.         INC     BYTE PTR FLGPCR         ; A. yes.. set the pcremote flag
  578.         MOV     BYTE PTR ZCPCR10+2,SEC_3 ; change the delay for modems
  579.         MOV     BYTE PTR ZCPCR20+2,SEC_3 ; change the delay for modems
  580.         MOV     BYTE PTR ZCPCR30+2,SEC_3 ; change the delay for modems
  581.         JMP     ZCPARM10                ; .. continue scanning
  582. ZCPARMERR:  LEA     DX, PARMERR         ; dx -> invalid number of parms
  583.         CALL    ZCDIE            ; abort
  584. ZCPARM        ENDP
  585. ; ---------------------------------------------------------------------
  586. ; This routine gets the next character from the parm area in the DOS PSP.
  587. ; Entry: si -> next char to get.
  588. ; Exit: Char translated to upper case. al = character; si -> next character
  589. ; ---------------------------------------------------------------------
  590. ZCPARMC     PROC    NEAR
  591.         CMP     BYTE PTR [SI], 'a'      ; Q. below lower case a?
  592.         JB        ZCPARMC10            ; A. yes .. do not upcase
  593.         CMP     BYTE PTR [SI], 'z'      ; Q. above lower case z?
  594.         JA        ZCPARMC10            ; A. yes .. same
  595.         AND     BYTE PTR [SI], NOT 20H  ; .. translate to upper case
  596. ZCPARMC10:  LODSB                ; load the character in AL
  597.         RET                 ; .. and return to caller
  598. ZCPARMC     ENDP
  599. ; ---------------------------------------------------------------------
  600. ; This routine sets the appropriate argument pointer.
  601. ; Entry: si -> second character in argument.
  602. ; Exit: arg1 or arg2 pointer filled in. Carry set if more than 2 arguments
  603. ; ---------------------------------------------------------------------
  604. ZCARG        PROC    NEAR
  605.         LEA     BX, [SI-1]            ; bx -> argument
  606.         CMP     ARG1, 0            ; Q. arg1 filled in?
  607.         JNE     ZCARG10            ; A. yes .. check 2
  608.         MOV     ARG1, BX            ; save arg1 pointer
  609.         JMP     SHORT ZCARG90        ; .. exit ok!
  610. ZCARG10:    CMP     ARG2, 0            ; Q. arg2 filled in?
  611.         JE        ZCARG20            ; A. no .. fill it in
  612.         STC                 ; else .. error
  613.         RET                 ; .. and return to caller
  614. ZCARG20:    MOV     ARG2, BX            ; save arg2 pointer
  615. ZCARG90:    CLC                 ; show no error
  616.         RET                 ; return to caller
  617. ZCARG        ENDP
  618. ; ---------------------------------------------------------------------
  619. ; This routine determines whether we are the sender or receiver
  620. ; and which communication port is to be used.
  621. ; Entry: ARG1, ARG2 must be set, one pointing to COMx with an optional colon
  622. ; Exit: Send/receive flag is set properly. IO_BASE and INT_VECTOR are set.
  623. ;    Exits to DOS if no COM port or 2 COM ports specified.
  624. ; ---------------------------------------------------------------------
  625. ZCCOM        PROC    NEAR
  626.         MOV     SI, ARG1            ; si -> parm1
  627.         CALL    ZCCOMP            ; Q. receiver?
  628.         JC        ZCCOM10            ; A. no .. check parm2
  629.         OR        FLG, FLGR            ; else .. set receiver mode
  630. ZCCOM10:    MOV     BL, FLG            ; bx = flags
  631.         MOV     SI, ARG2            ; si -> parm2
  632.         CALL    ZCCOMP            ; Q. sender?
  633.         JC        ZCCOM20            ; A. no .. assure receiver
  634.         TEST    BL, FLGR            ; Q. Are we receiver?
  635.         JZ        ZCCOM80            ; A. No .. parms ok
  636. ZCCOM15:    LEA     DX, PARMERR         ; dx -> parameter error
  637.         CALL    ZCDIE            ; .. die gracefully
  638. ZCCOM20:    TEST    BL, FLGR            ; Q. Are we a receiver?
  639.         JZ        ZCCOM15            ; A. no .. issue error
  640. ZCCOM80:    CMP     AL, 1            ; Q. COM1?
  641.         JNE     ZCCOM85            ; A. no .. set up for COM2.
  642.         MOV     IO_BASE, 3F8H        ; set base port address
  643.         MOV     INT_VECTOR, 4        ; .. and interrupt number
  644.         RET                 ; return to caller
  645. ZCCOM85:    CMP     AL, 2                   ; Q. COM2?
  646.             JNE     ZCCOM90                 ; A. no .. check for COM3.
  647.         MOV     IO_BASE, 2F8H        ; set base port address
  648.         MOV     INT_VECTOR, 3        ; .. and interrupt number
  649.         RET                 ; return to caller
  650. ZCCOM90:    CMP     AL, 3                   ; Q. COM3?
  651.             JNE     ZCCOM95                 ; A. no .. check for COM4.
  652.         MOV     AX,COMM_PORT3
  653.         MOV     IO_BASE, AX         ; set base port address
  654.         MOV     AL, BYTE PTR COMM3_INT
  655.         MOV     INT_VECTOR, AL        ; .. and interrupt number
  656.         RET                 ; return to caller
  657. ZCCOM95:    MOV     AX,COMM_PORT3
  658.         MOV     IO_BASE, AX         ; set base port address COM4
  659.         MOV     AL, BYTE PTR COMM4_INT
  660.         MOV     INT_VECTOR, AL        ; .. and interrupt number
  661.         RET                 ; return to caller
  662. ZCCOM        ENDP
  663. ; ---------------------------------------------------------------------
  664. ; This routine looks for a valid COMx: in the passed parameter.
  665. ; Entry: si -> string to check
  666. ; Exit: Carry set if not COMx: string; al = 1 or 2 for COM1: or COM2:
  667. ; ---------------------------------------------------------------------
  668. ZCCOMP        PROC    NEAR
  669.         PUSH    BX                ; save bx
  670.         MOV     BX, SI            ; bx -> argument
  671.         CLD                 ; set direction
  672.         LEA     DI, COM_STR         ; di -> 'COM'
  673.         MOV     CX, 3            ; cx = length of string
  674.      REPE   CMPSB                ; Q. 'COM' start the string?
  675.         JE        ZCCOMP10            ; A. yes.. continue
  676. ZCCOMP05:   STC                 ; show not a com port
  677.         POP     BX                ; restore bx
  678.         RET                 ; .. return to caller
  679. ZCCOMP10:   CMP     BYTE PTR [BX+4], ':'    ; Q. end in colon?
  680.         JE        ZCCOMP30            ; A. yes .. check which port
  681.         CMP     BYTE PTR [BX+4], 0        ; Q. non-colon end?
  682.         JNE     ZCCOMP05            ; A. no .. not a com parameter
  683. ZCCOMP30:   MOV     AL, [BX+3]            ; ah = ascii com port number.
  684.         SUB     AL, 30H            ; ah = binary com port number.
  685.         CMP     AL, 1            ; Q. below COM1?
  686.         JB        ZCCOMP05            ; A. yes .. invalid com port
  687.         CMP     AL, 4            ; Q. above com4?
  688.         JA        ZCCOMP05            ; A. yes .. invalid com port
  689.         CLC                 ; else .. good com port
  690.         POP     BX                ; restore bx
  691.         RET                 ; .. return to caller
  692. ZCCOMP        ENDP
  693. ; ---------------------------------------------------------------------
  694. ; This routine displays an error message and terminates.
  695. ; Entry: dx -> error message ended in dollar sign.
  696. ; Exit: Exits to DOS
  697. ; ---------------------------------------------------------------------
  698. ZCDIE        PROC    NEAR
  699.         TEST    FLG1, FLG1I         ; Q. initialized?
  700.         JZ        ZCDIE10            ; A. no .. print & return
  701.         PUSH    DX                ; else .. save message address
  702.         CALL    ZCRESET            ; .. reset system
  703.         POP     DX                ; .. restore message address
  704. ZCDIE10:    MOV     AH, 9            ; ah = print string
  705.         INT     21H             ; .. call dos to print error
  706.         MOV     AX, 4C01H            ; ax = exit
  707.         INT     21H             ; .. terminate routine
  708. ZCDIE        ENDP
  709. ; ---------------------------------------------------------------------
  710. ; This routine changes all arguments on the command line to upper case
  711. ; ---------------------------------------------------------------------
  712. ZCUC        PROC    NEAR
  713.         PUSH    SI                ; save caller regs
  714.         PUSH    DI
  715.         MOV     SI, 81H            ; si -> start of parm area
  716.         MOV     DI, SI            ; .. same for di
  717. ZCUC10:     LODSB                ; al = char
  718.         CMP     AL, 13            ; Q. end of line?
  719.         JE        ZCUC90            ; A. yes .. end of line!
  720.         CMP     AL, 'a'                 ; Q. is it below 'a'?
  721.         JB        ZCUC20            ; A. yes .. continue
  722.         CMP     AL, 'z'                 ; Q. is it above 'z'?
  723.         JA        ZCUC20            ; A. yes .. continue
  724.         SUB     AL, 20H            ; set to upper case
  725. ZCUC20:     STOSB                ; save the byte
  726.         JMP     ZCUC10            ; .. and continue
  727. ZCUC90:     POP     DI                ; restore caller regs
  728.         POP     SI
  729.         RET                 ; .. and return to caller
  730. ZCUC        ENDP
  731. ; ---------------------------------------------------------------------
  732. ; This routine sets the default drive and path.
  733. ; On the sending machine, the file name is also set up.
  734. ; ---------------------------------------------------------------------
  735. ZCFLSET     PROC    NEAR
  736.         MOV     DI, ARG1            ; di -> first arg
  737.         TEST    FLG, FLGR            ; Q. receiver?
  738.         JZ        ZCFLSET10            ; A. no .. continue
  739.         MOV     DI, ARG2            ; di -> second arg
  740. ZCFLSET10:  CMP     BYTE PTR [DI+1], ':'    ; Q. drive specified?
  741.         JNE     ZCFLSET20            ; A. no .. use current drive
  742.         MOV     DL, [DI]            ; dl = drive to use
  743.         SUB     DL, 'A'                 ; get requested drive number
  744.         MOV     AH, 0EH            ; set requested drive
  745.         INT     21H             ; .. via dos
  746.         ADD     DI, 2            ; di -> next part
  747. ZCFLSET20:  TEST    FLG, FLGR            ; Q. receiver?
  748.         JNZ     ZCFLSET50            ; A. yes .. filename not used
  749.         PUSH    DI                ; save pointer
  750.         MOV     BX, DI            ; bx -> start of area
  751.         XOR     AL, AL            ; al = search for null
  752.         MOV     CX, 128            ; very max to search
  753.         CLD
  754.     REPNE   SCASB                ; find end of arg
  755.         LEA     SI, [DI-1]            ; si -> nul
  756.         MOV     CX, 0            ; cx = # chars to move
  757.         CMP     SI, BX            ; Q. any file name
  758.         JE        ZCFLSET80            ; A. no .. error
  759. ZCFLSET30:  DEC     SI                ; si -> prev char
  760.         CMP     BYTE PTR [SI], '\'      ; Q. dir?
  761.         JE        ZCFLSET35            ; A. yes .. end of file name.
  762.         INC     CX                ; cx = char count
  763.         CMP     SI, BX            ; Q. done?
  764.         JE        ZCFLSET37            ; A. yes .. move file name
  765.         JMP     ZCFLSET30            ; .. continue
  766. ZCFLSET35:  INC     SI                ; si -> start of file name
  767. ZCFLSET37:  OR        CX, CX            ; Q. file name spec'd?
  768.         JZ        ZCFLSET80            ; A. no .. error
  769.         CMP     CX, 12            ; Q. too long?
  770.         JA        ZCFLSET85            ; A. yes .. error
  771.         PUSH    SI                ; save start pointer
  772.         MOV     DI, OFFSET FILENAME     ; di -> file name
  773.      REP    MOVSB                ; .. move in the file name
  774.         POP     SI                ; restore start pointer
  775.         POP     DI                ; .. and dir pointer
  776.         CMP     SI, BX            ; Q. at start of parm?
  777.         JE        ZCFLSET90            ; A. yes .. return
  778.         INC     BX                ; bx -> next char
  779.         CMP     SI, BX            ; Q. root only given?
  780.         JE        ZCFLSET40            ; A. yes .. continue
  781.         DEC     SI                ; si -> last \
  782. ZCFLSET40:  MOV     BYTE PTR [SI], 0        ; make dir ASCIIZ
  783. ZCFLSET50:  MOV     DX, DI            ; dx -> directory
  784.         MOV     AH, 3BH            ; ah = CHDIR opcode
  785.         INT     21H             ; .. change directory
  786.         JNC     ZCFLSET90            ; if ok .. continue
  787.         MOV     DX, OFFSET BADDIR        ; dx -> baddir request
  788.         CALL    ZCDIE            ; .. die now
  789. ZCFLSET80:  MOV     DX, OFFSET FILERR        ; dx -> no file specified
  790.         CALL    ZCDIE
  791. ZCFLSET85:  MOV     DX, OFFSET INVFIL        ; dx -> invalid filename spec'd
  792.         CALL    ZCDIE
  793. ZCFLSET90:  RET                 ; return to caller
  794. ZCFLSET     ENDP
  795. ; ---------------------------------------------------------------------
  796. ; This routine waits for n nbr of timer ticks to transpire.
  797. ; Entry: ax = nbr of timer ticks to wait
  798. ; ---------------------------------------------------------------------
  799. ZCWAIT        PROC    NEAR
  800.         ADD     AX, WAIT_COUNT        ; ax = count to wait till
  801. ZCWAIT10:   CMP     WAIT_COUNT, AX        ; Q. enough time elapsed?
  802.         JNA     ZCWAIT10            ; A. no .. loop
  803.         CALL    ZCTIMUP            ; .. update system timer
  804.         RET                 ; finally, return to caller
  805. ZCWAIT        ENDP
  806. ; ---------------------------------------------------------------------
  807. ; This routine retrieves the most recent LSR value.
  808. ; Exit: carry set if new value is found.; al = last LSR value detected.
  809. ; ---------------------------------------------------------------------
  810. ZCLSRGET    PROC    NEAR
  811.         CLI                 ; no interrupts
  812.         MOV     AL, LSR_VAL         ; al = last known LSR value
  813.         OR        LSR_NEW, 0            ; check if value is new
  814.         MOV     LSR_NEW, 0            ; .. reset it
  815.         STI                 ; .. allow interrupts
  816.         JNZ     ZCLSRGET90            ; .. jump if new value
  817.         CLC                 ; show no new value
  818.         RET                 ; .. and return to caller
  819. ZCLSRGET90: STC                 ; show new value
  820.         RET                 ; .. and return to caller
  821. ZCLSRGET    ENDP
  822. ; ---------------------------------------------------------------------
  823. ; This routine sends a break .2 seconds long.
  824. ; ---------------------------------------------------------------------
  825. ZCBREAK     PROC    NEAR
  826.         PUSH    AX                ; save caller regs
  827.         PUSH    BX
  828.         PUSH    DX
  829.         MOV     DX, IO_BASE         ; dx -> comm base register
  830.         ADD     DX, 3            ; dx = line control reg addr
  831.         IN        AL, DX            ; al = LCR contents
  832.         MOV     BL, AL            ; bl = LCR
  833.         OR        AL, 40H            ; .. turn on break bit
  834.         OUT     DX, AL            ; .. send a break
  835.         MOV     AX, 4            ; wait 4 ticks (~ .2 secs)
  836.         CALL    ZCWAIT            ; .. wait ...
  837.         AND     AL,NOT 40H            ; assure no break bit
  838.         MOV     AL,BL            ; al = old LSR contents
  839.         OUT     DX, AL            ; end the break
  840.         POP     DX                ; restore registers
  841.         POP     BX
  842.         POP     AX
  843.         RET                 ; return to caller
  844. ZCBREAK     ENDP
  845. ; ---------------------------------------------------------------------
  846. ; This routine clears the incomming buffer by resetting the buffer pointers.
  847. ; ---------------------------------------------------------------------
  848. ZCCLRCOM    PROC    NEAR
  849.         PUSH    RBUF_RPTR            ; push the receive pointer
  850.         POP     RBUF_GPTR            ; .. and pop get pointer
  851.         RET                 ; .. and return to caller
  852. ZCCLRCOM    ENDP
  853. ; ---------------------------------------------------------------------
  854. ; This routine tests if a break was recently detected.
  855. ; Exit: returns NZ if break found, zero if not.
  856. ; ---------------------------------------------------------------------
  857. ZCTSTBRK    PROC    NEAR
  858.         PUSH    AX                ; save caller registers
  859.         CALL    ZCLSRGET            ; get LSR value
  860.         JC        ZCTSTBRK80            ; .. test value if found
  861.         SUB     AH, AH            ; assure zero flag set
  862.         JMP     SHORT ZCTSTBRK90        ; .. return to caller
  863. ZCTSTBRK80: TEST    AL, LSR_BRK         ; Q. BREAK occur?
  864. ZCTSTBRK90: POP     AX                ; restore ax
  865.         RET                 ; return to caller
  866. ZCTSTBRK    ENDP
  867. ; ---------------------------------------------------------------------
  868. ; This routine will setup the baud rate for the com port.
  869. ; Entry: ax = baud rate index
  870. ; 0=115.2kb, 1=57.6kb, 2=38.4kb, 3=19.2kb, 4=9600, 5=4800
  871. ; 6=2400, 7=1200
  872. ; ---------------------------------------------------------------------
  873. ZCBAUD        PROC    NEAR
  874.         PUSH    AX                ; save registers
  875.         PUSH    BX
  876.         PUSH    DX
  877.         PUSH    AX                ; save ax
  878.         MOV     DX, OFFSET TRYING        ; dx -> baud message
  879.         MOV     AH, 9            ; ah = print "$" message
  880.         INT     21H             ; .. tell 'em what we're doing
  881.         POP     AX                ; restore baud request
  882.         MOV     BX, AX            ; bx = baud index
  883.         MOV     CL, 3            ; .. shift for * 8
  884.         SHL     BX, CL            ; bx = baud index * 8
  885.         SUB     BX, AX            ; .. make that * 7
  886.         LEA     DX, BAUD_TABLE+1[BX]    ; dx -> $ message
  887.         MOV     BL, BAUD_TABLE[BX]        ; bl = divisor
  888.         XOR     BH, BH            ; .. upper byte off
  889.         MOV     AH, 9H            ; ah = print '$' message
  890.         INT     21H             ; .. display baud rate
  891.         TEST    FLG1, FLG1B         ; Q. ctl-break?
  892.         JZ        ZCBAUD10            ; A. no .. continue
  893.         MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> shutdown msg
  894.         CALL    ZCDIE            ; .. end it all
  895. ZCBAUD10:   CMP     BYTE PTR FLGPCR, 0      ; Q. pcremote active?
  896.             JNZ     ZCBAUD20                ; A. yes.. don't change baud
  897.             MOV     DX, IO_BASE         ; dx = io port base addr
  898.         ADD     DX, 3            ; dx = line control register
  899.         IN        AL, DX            ; al = lcr
  900.         OR        AL, LCR_DLAB        ; al = divisor latch enable
  901.         CLI                 ; stop interrupts, then ..
  902.         OUT     DX, AL            ; enable the setting of the dlab
  903.         SUB     DX, 3            ; dx = LSB port of divisor latch
  904.         MOV     AL, BL            ; al = LSB of new divisor
  905.         OUT     DX, AL            ; output the LSB portion
  906.         INC     DX                ; dx = MSB port of divisor latch
  907.         MOV     AL, BH            ; al = MSB of new divisor
  908.         OUT     DX, AL            ; output the MSB portion
  909.         ADD     DX, 2            ; dx = line control register
  910.         IN        AL, DX            ; al = lcr
  911.         AND     AL, NOT LCR_DLAB        ; .. set off dlab
  912.         OUT     DX, AL            ; .. restore line control register
  913.         STI                 ; .. and re-enable interrupts
  914. ZCBAUD20:   POP     DX                ; restore caller's registers
  915.         POP     BX
  916.         POP     AX
  917.         RET                 ; ..and return to caller
  918. ZCBAUD        ENDP
  919. ; ---------------------------------------------------------------------
  920. ; This routine tests for the highest possible baud rate.
  921. ; ---------------------------------------------------------------------
  922. ZCSPEED     PROC    NEAR
  923.         PUSH    AX                ; save register
  924.             CMP     BYTE PTR FLGPCR, 0      ; Q. PCREMOTE active
  925.         JZ      ZCSPEED05               ; A. no
  926.             MOV     AL, BAUD_CNTR        ; al = baud rate counter
  927.         CBW                 ; ax = baud rate counter
  928.         CALL    ZCBAUD            ; .. setup baud rate
  929.         JMP     ZCSPEED90               ; A. yes, assume bauds match
  930. ZCSPEED05:  CMP        BAUD_CNTR, 8            ; Comm attempts done ?
  931.         JB        ZCSPEED10            ; A. no .. try again
  932.         MOV     DX, OFFSET SPDERROR     ; dx -> Comm not possible
  933.         CALL    ZCDIE            ; die now
  934. ZCSPEED10:  MOV     AL, BAUD_CNTR        ; al = baud rate counter
  935.         CBW                 ; ax = baud rate counter
  936.         CALL    ZCBAUD            ; .. setup baud rate
  937.         MOV     AX, 2            ; wait .1 sec
  938.         CALL    ZCWAIT            ; .. for all to calm down
  939.         MOV     WAIT_COUNT, 0        ; .. and wait counter
  940.         CALL    ZCCLRCOM            ; .. clear out receive buffer
  941. ZCSPEED11:  MOV     AL, STX            ; al = send stx
  942.         CALL    ZCPUTC            ; .. send char
  943.         MOV     AX, 1            ; wait 1 tick
  944.         CALL    ZCWAIT            ; .. wait
  945.         CALL    ZCGETC            ; Q. char available?
  946.         JC        ZCSPEED15            ; A. no .. try again
  947.         CMP     AL, STX            ; Q. stx?
  948.         JE        ZCSPEED17            ; A. yes .. continue
  949. ZCSPEED15:  TEST    FLG1, FLG1B         ; Q. ctl-break?
  950.         JNZ     ZCSPEED16            ; A. yes .. end it now
  951.         TEST    FLG, FLGW            ; Q. wait forever?
  952.         JNZ     ZCSPEED11            ; A. yes .. do so.
  953.         MOV     AX, DSRWAIT         ; ax = current wait count
  954.         CMP     WAIT_COUNT, AX        ; Q. time expire?
  955.         JNA     ZCSPEED11            ; A. no.. try again
  956.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  957.         CALL    ZCDIE            ; .. die gracefully
  958. ZCSPEED16:  MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> ZCOPY done msg
  959.         CALL    ZCDIE            ; .. end gracefully
  960. ZCSPEED17:  CALL    ZCCLRCOM            ; clear receive buffer
  961.         CALL    ZCLSRGET            ; assure old lsr killed
  962.         MOV     DSRWAIT, SEC_3        ; reset dsrwait
  963.         TEST    FLG,FLGR            ; Q. are we the receiver?
  964.         JNZ     ZCSPEED50            ; A. yes .. sync as such
  965. ; SENDING NODE
  966.         CALL    ZCSPDA            ; Q. first part ok?
  967.         JC        ZCSPEED80            ; A. no .. try next baud
  968.         CALL    ZCSPDB            ; Q. second part ok?
  969.         JC        ZCSPEED80            ; A. no .. try next baud
  970.         JMP     SHORT ZCSPEED90        ; else.. exit ok
  971. ; RECEIVING NODE
  972. ZCSPEED50:  CALL    ZCSPDB            ; Q. answer to first part ok?
  973.         JC        ZCSPEED80            ; A. no .. try next baud
  974.         CALL    ZCSPDA            ; Q. answer to second ok?
  975.         JNC     ZCSPEED90            ; A. no .. try next baud
  976. ZCSPEED80:  INC     BAUD_CNTR            ; next baud rate
  977.             CMP     BYTE PTR FLGPCR, 0      ; Q. PCREMOTE active
  978.         JZ      ZCSPEED85               ; A. no .. try next baud
  979.         DEC     BAUD_CNTR               ; A. yes.. don't change baud
  980. ZCSPEED85:  JMP     ZCSPEED05            ; .. try re-sync
  981. ZCSPEED90:  CALL    ZCCLRCOM            ; assure all bytes cleared
  982.         MOV     DX, OFFSET SPDSET        ; dx -> ok message
  983.         MOV     AH, 9            ; ah = print to "$"
  984.         INT     21H             ; display message
  985.         POP     AX                ; restore caller's regs
  986.         RET                 ; .. and return to caller
  987. ZCSPEED     ENDP
  988. ; ---------------------------------------------------------------------
  989. ; This routine is one side of the set baud rate routine -- sender.
  990. ; Exit: Carry set if unsuccessful.
  991. ; ---------------------------------------------------------------------
  992. ZCSPDA        PROC    NEAR
  993.         MOV     DX, WAIT_COUNT        ; dx = current wait count
  994.         ADD     DX, 6            ; dx = future wait count
  995. ZCSPDA12:   MOV     AL, SYNC_BYTE        ; al = start signature byte
  996.         CALL    ZCPUTC            ; .. put it out
  997.         MOV     AX, 1            ; ax = wait 1 tick
  998.         CALL    ZCWAIT            ; .. wait 1 tick
  999.         CALL    ZCGETC            ; Q. char available?
  1000.         JC        ZCSPDA17            ; A. no .. continue
  1001.         CMP     AL, STX            ; Q. stx?
  1002.         JNE     ZCSPDA15            ; A. no .. continue
  1003.         CALL    ZCPUTC            ; .. send STX back
  1004.         JMP     ZCSPDA12            ; .. and do it again
  1005. ZCSPDA15:   CMP     AL, ACK            ; Q. ack?
  1006.         JE        ZCSPDA20            ; A. yes .. send sync string
  1007. ZCSPDA17:   CMP     DX, WAIT_COUNT        ; Q. time up?
  1008.         JA        ZCSPDA12            ; A. no .. try again
  1009.         JMP     SHORT ZCSPDA80        ; return unsuccessful
  1010. ;    SYNC BYTE RECEIVED .. SEND STRING
  1011. ZCSPDA20:   MOV     AL, SYNC_END        ; al = end of sync sequence
  1012.         CALL    ZCPUTC            ; .. write it
  1013.         MOV     CX, SYNC_LEN        ; Length of sync string
  1014.         XOR     AL, AL            ; al = sync char
  1015. ZCSPDA25:   CALL    ZCPUTC            ; put out sync string char
  1016.         ADD     AL, SYNC_INC        ; .. calc next char
  1017.         LOOP    ZCSPDA25            ; .. continue until done
  1018.         MOV     AX, 9            ; ax = .5 sec
  1019.         CALL    ZCWAIT            ; .. wait .5 secs
  1020.         CALL    ZCTSTBRK            ; Q. did break occur?
  1021.         JNZ     ZCSPDA90            ; A. yes .. return successful
  1022. ZCSPDA80:   STC                 ; return unsuccessful
  1023.         RET                 ; .. return to caller
  1024. ZCSPDA90:   CLC                 ; return successful
  1025.         RET                 ; .. return to caller
  1026. ZCSPDA        ENDP
  1027. ; ---------------------------------------------------------------------
  1028. ; This routine is one side of the set baud rate routine -- receiver.
  1029. ; Exit: Carry set if unsuccessful.
  1030. ; ---------------------------------------------------------------------
  1031. ZCSPDB        PROC    NEAR
  1032.         MOV     WAIT_COUNT, 0        ; set wait counter to 0
  1033. ZCSPDB10:   CALL    ZCGETC            ; Q. char available?
  1034.         JNC     ZCSPDB20            ; A. yes .. check it.
  1035.         CMP     WAIT_COUNT, 19        ; Q. 1 second?
  1036.         JB        ZCSPDB10            ; A. no .. keep trying.
  1037.         JMP     SHORT ZCSPDB80        ; else .. return unsuccessful
  1038. ZCSPDB20:   CMP     AL, SYNC_BYTE        ; Q. sync byte received?
  1039.         JNE     ZCSPDB25            ; A. yes .. answer it.
  1040.         MOV     AL, ACK            ; al = ack
  1041.         CALL    ZCPUTC            ; .. tell 'em wt got it.
  1042.         JMP     ZCSPDB10            ; .. try for sync_end
  1043. ZCSPDB25:   CMP     AL, SYNC_END        ; Q. end of sync bytes?
  1044.         JE        ZCSPDB30            ; A. yes .. expect sync string.
  1045.         CMP     AL, STX            ; Q. still stxing?
  1046.         JNE     ZCSPDB10            ; A. no .. continue
  1047.         CALL    ZCPUTC            ; else .. tell 'em we got it
  1048.         JMP     ZCSPDB10            ; .. and try again
  1049. ZCSPDB30:   CALL    ZCSPDCHK            ; Q. block receive ok?
  1050.         JC        ZCSPDB80            ; A. no .. return unsuccessful
  1051.         CALL    ZCBREAK            ; else .. tell 'em we're talking
  1052.         JMP     SHORT ZCSPDB90        ; .. and return to caller
  1053. ZCSPDB80:   MOV    AX, SEC_1            ; wait 1 second ...
  1054.         CALL   ZCWAIT            ; .. wait
  1055.         STC                 ; return unsuccessful
  1056.         RET                 ; .. return to caller
  1057. ZCSPDB90:   CLC                 ; return successful
  1058.         RET                 ; .. return to caller
  1059. ZCSPDB        ENDP
  1060. ; ---------------------------------------------------------------------
  1061. ; This routine calculates a CRC for a block of characters.
  1062. ; Entry: si -> character block; cx = # characters to include in calc
  1063. ; Exit: ax = CRC
  1064. ; ---------------------------------------------------------------------
  1065. ZCCRC        PROC    NEAR
  1066.         PUSH    SI                ; save caller regs
  1067.         PUSH    BX
  1068.         PUSH    CX
  1069.         XOR     AX, AX            ; ax = start value (0)
  1070.         ADD     CX, 2            ; do 2 "additional" bytes
  1071. ZCCRC05:    PUSH    CX                ; save cx
  1072.         MOV     BL, BYTE PTR [SI]        ; bl = next byte
  1073.         INC     SI                ; si -> next character
  1074.         CMP     CX, 2            ; Q. more than 2 chars left?
  1075.         JA        ZCCRC08            ; A. yes .. continue
  1076.         MOV     BL, 0FFH            ; .. set to 0ffh
  1077. ZCCRC08:    MOV     CX, 8            ; 8 bits ..
  1078. ZCCRC10:    XOR     BH, BH            ; clear bh
  1079.         SHL     BX, 1            ; shift the next char
  1080.         SHL     AX, 1            ; Q. high bit on?
  1081.         JNC     ZCCRC20            ; A. no .. do not xor CRC value
  1082.         OR        AL, BH            ; .. include the next bit
  1083.         XOR     AX, CRC_VAL         ; .. xor the CRC value
  1084.         LOOP    ZCCRC10            ; loop 'til done
  1085.         JMP     SHORT ZCCRC30        ; .. continue when done
  1086. ZCCRC20:    OR        AL, BH            ; include the next bit
  1087.         LOOP    ZCCRC10            ; loop 'til done
  1088. ZCCRC30:    POP     CX                ; restore char count
  1089.         LOOP    ZCCRC05            ; .. continue until done
  1090.         POP     CX                ; restore caller's regs
  1091.         POP     BX
  1092.         POP     SI
  1093.         RET
  1094. ZCCRC        ENDP
  1095. ; ---------------------------------------------------------------------
  1096. ; This routine builds a block and sends it to the other machine.
  1097. ; Block Format: STX crc(2) len(2) blk#(2) cmd(1) data(n) ETX
  1098. ; where: STX=02h, crc=16 bit error check value, len=length of block (i.e.
  1099. ; data length+3), blk#=number of this block, 0 thru 65535, wrapping
  1100. ; cmd=command/identifier for this block, data=send characters, ETX=03h
  1101. ; Entry: al=command; si->chars to send; cx=# chars to include in calc
  1102. ; Exit: Returns when transmission complete.
  1103. ; ---------------------------------------------------------------------
  1104. ZCBLKSND    PROC    NEAR
  1105.         PUSH    AX                ; save caller's regs
  1106.         PUSH    BX
  1107.         PUSH    DX
  1108.         PUSH    SI
  1109.         PUSH    DI
  1110.         PUSH    CX
  1111.         MOV     DI, SBUF            ; di -> send buffer
  1112.         TEST    FLG1, FLG1B         ; Q. control-break detected?
  1113.         JZ        ZCBLKSND05            ; A. no .. continue
  1114.         MOV     AL, DIENOW            ; al = die now command
  1115.         OR        FLG1, FLG1S         ; .. show shutdown sent
  1116. ZCBLKSND05: PUSH    AX
  1117.         CLD                 ; we want to increment
  1118.         MOV     AL, STX            ; al = stx value
  1119.         STOSB                ; .. save in send buffer
  1120.         ADD     DI, 2            ; di -> past CRC bytes
  1121.         MOV     AX, CX            ; ax = characters string len
  1122.         ADD     AX, 3            ; ax = chars + cmd + blk# len
  1123.         STOSW                ; .. save the length
  1124.         MOV     AX, SEND_BLKNO        ; ax = next send block number
  1125.         STOSW                ; save send block number
  1126.         POP     AX                ; restore the command
  1127.         STOSB                ; save the command
  1128.         JCXZ    ZCBLKSND10            ; jump if no bytes to move
  1129.      REP    MOVSB                ; .. move in the chars
  1130. ZCBLKSND10: MOV     AL, ETX            ; al = etx value
  1131.         STOSB                ; .. save at end of buffer
  1132.         MOV     BX, SBUF            ; bx -> buffer
  1133.         MOV     CX, [BX+MLEN]        ; cx = blk#+cmd+data len
  1134.         LEA     SI, [BX+MBLKNO]        ; si -> blk#/cmd/data area
  1135.         CALL    ZCCRC            ; calculate the crc
  1136.         MOV     [BX+MCRC], AX        ; .. save in the buffer
  1137.         MOV     DL, RETRIES         ; dl = max retries
  1138. ZCBLKSND20: MOV     SI, BX            ; si -> buffer
  1139.         MOV     CX, [BX+MLEN]        ; cx = blk#/cmd/data length
  1140.         ADD     CX, MOHEAD            ; characters to send
  1141. ZCBLKSND25: LODSB                ; al = char to send
  1142.         CALL    ZCPUTC            ; .. send it
  1143.         LOOP    ZCBLKSND25            ; .. loop until all sent
  1144.         MOV     BX, WAIT_COUNT        ; bx = now
  1145.         ADD     BX, SEC_10            ; bx = later, 10 seconds
  1146. ZCBLKSND35: CALL    ZCWAITC            ; .. and wait for a character
  1147.         JC        ZCBLKSND60            ; .. timeout .. see if any resp
  1148.         CMP     AL, ACK            ; Q. send ok?
  1149.         JE        ZCBLKSND80            ; A. yes .. continue
  1150.         CMP     AL, NAK            ; Q. send bad?
  1151.         JE        ZCBLKSND75            ; A. yes .. restart send
  1152.         CMP     AL, RLR            ; Q. request last response
  1153.         JE        ZCBLKSND50            ; A. yes .. continue
  1154.         JMP     SHORT ZCBLKSND70        ; .. clear buffer, retry
  1155. ZCBLKSND50: CALL    ZCGETC            ; kill the rlr
  1156.         MOV     AL, LAST_RESP        ; al = last response sent
  1157.         CALL    ZCPUTC            ; .. tell the other machine
  1158.         MOV     BX, SBUF            ; bx -> buffer
  1159.         JMP     ZCBLKSND20            ; .. and resend our block
  1160. ZCBLKSND60: CMP     WAIT_COUNT, BX        ; Q. 10 seconds yet
  1161.         JB        ZCBLKSND65            ; A. no .. continue
  1162.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  1163.         CALL    ZCDIE            ; .. and die now
  1164. ZCBLKSND65: MOV     AL, RLR            ; al = get last response
  1165.         CALL    ZCPUTC            ; .. request last response
  1166.         INC     ERRORS            ; .. increment the error count
  1167.         JMP     ZCBLKSND35            ; .. and ask other machine
  1168. ZCBLKSND70: CALL    ZCGETC            ; get a char
  1169.         CALL    ZCWAITC            ; .. wait for another to arrive
  1170.         JNC     ZCBLKSND70            ; .. if another does, get it
  1171.         JMP     ZCBLKSND65            ; .. get last response now.
  1172. ZCBLKSND75: CALL    ZCGETC            ; .. kill the nak
  1173.         INC     ERRORS            ; increment error count
  1174.         MOV     BX, SBUF            ; bx -> buffer
  1175.         JMP     ZCBLKSND20            ; .. retry
  1176. ZCBLKSND80: CALL    ZCGETC            ; kill the character
  1177.         INC     SEND_BLKNO            ; next send block number
  1178.         TEST    FLG1, FLG1S         ; Q. shutdown sent?
  1179.         JZ        ZCBLKSND90            ; A. no .. continue
  1180.         MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> shutdown request
  1181.         CALL    ZCDIE            ; .. and end it all
  1182. ZCBLKSND90: POP     CX                ; restore length
  1183.         POP     DI
  1184.         POP     SI
  1185.         POP     DX
  1186.         POP     BX
  1187.         POP     AX
  1188.         RET
  1189. ZCBLKSND    ENDP
  1190. ; ---------------------------------------------------------------------
  1191. ; This routine waits for a character, .5 secs.
  1192. ; Exit: carry=TIMEOUT; no carry=char received; al = character
  1193. ; ---------------------------------------------------------------------
  1194. ZCWAITC     PROC    NEAR
  1195.         PUSH    BX
  1196.         MOV     BX, WAIT_COUNT        ; bx = now ..
  1197. ZCPCR10:    ADD     BX, 13            ; bx = later (.5 secs) ..
  1198. ZCWAITC10:  CALL    ZCCLA            ; Q. char available?
  1199.         JNC     ZCWAITC90            ; A. yes .. return
  1200.         CMP     WAIT_COUNT, BX        ; Q. .5 secs?
  1201.         JB        ZCWAITC10            ; A. no .. continue
  1202.         STC                 ; show timeout
  1203.         JMP     SHORT ZCWAITC90        ; .. return to caller
  1204. ZCWAITC90:  POP     BX                ; .. return to caller
  1205.         RET                 ; .. and return to caller
  1206. ZCWAITC     ENDP
  1207. ; ---------------------------------------------------------------------
  1208. ; This routine receives a block, checks CRC, ACKs its reception and places
  1209. ; the data in wbuf.  STX of block should have already been read and discarded
  1210. ; The block format is documented in ZCBLKSND.
  1211. ; Exit: Carry - block not available (timeout or bad crc).
  1212. ; No Carry - block received ok, in wbuf, starting w/CRC; al = command byte
  1213. ; ---------------------------------------------------------------------
  1214. ZCBLKRCV    PROC    NEAR
  1215.         PUSH    BX                ; save regs
  1216.         PUSH    CX
  1217.         PUSH    DX
  1218.         PUSH    DI
  1219.         PUSH    SI
  1220.         MOV     BX, WAIT_COUNT        ; bx = current timer
  1221. ZCPCR20:    ADD     BX, 5            ; bx = max time to wait until
  1222.         MOV     CX, 0            ; zero out char counter
  1223.         MOV     DI, WBUF            ; di -> wbuf
  1224.         ADD     DI, MCRC            ; di -> work buffer crc field
  1225.         MOV     DX, -1            ; .. dummy # chars needed
  1226. ZCBLKRCV10: CALL    ZCGETC            ; Q. char available?
  1227.         JC        ZCBLKRCV30            ; A. no .. error
  1228.         MOV     BX, WAIT_COUNT        ; bx = current timer
  1229. ZCPCR30:    ADD     BX, 5            ; .. next time to wait until
  1230.         STOSB                ; put in wbuf
  1231.         INC     CX                ; cx = # chars
  1232.         CMP     CX, 4            ; Q. len in yet?
  1233.         JNE     ZCBLKRCV20            ; A. no .. continue
  1234.         MOV     DX, [DI-2]            ; dx = message len
  1235.         ADD     DX, 5            ; dx = # character needed
  1236. ZCBLKRCV20: CMP     CX, DX            ; Q. enough chars received?
  1237.         JE        ZCBLKRCV50            ; A. yes .. check 'em out.
  1238.         JMP     SHORT ZCBLKRCV10        ; else .. get another
  1239. ZCBLKRCV30: CMP     WAIT_COUNT, BX        ; Q. timeout?
  1240.         JA        ZCBLKRCV70            ; A. yes .. NAK
  1241.         JMP     SHORT ZCBLKRCV10        ; .. try again
  1242. ZCBLKRCV50: MOV     SI, WBUF            ; si -> wbuf
  1243.         MOV     CX, [SI+MLEN]        ; dx = length
  1244.         PUSH    SI                ; save wbuf pointer
  1245.         LEA     SI, [SI+MBLKNO]        ; si -> blk#
  1246.         CALL    ZCCRC            ; .. calc crc
  1247.         POP     SI                ; si -> wbuf
  1248.         CMP     AX, [SI+MCRC]        ; Q. crc same?
  1249.         JE        ZCBLKRCV55            ; A. yes .. ok
  1250.         JMP     SHORT ZCBLKRCV70        ; .. else .. NAK
  1251. ZCBLKRCV55: MOV     AX, RCV_BLKNO        ; ax = expected block
  1252.         CMP     AX, [SI+MBLKNO]        ; Q. same block?
  1253.         JE        ZCBLKRCV80            ; A. yes .. continue
  1254.         CALL    ZCCLRCOM            ; else .. clear com buffer
  1255.         MOV     AL, ACK            ; al = ack
  1256.         MOV     LAST_RESP, AL        ; .. save as last resp
  1257.         CALL    ZCPUTC            ; .. ack last block
  1258.         STC                 ; show no receive
  1259.         JMP     SHORT ZCBLKRCV90        ; .. return to caller
  1260. ZCBLKRCV70: MOV     AL, RLR            ; al = NAK
  1261.         MOV     LAST_RESP, AL        ; .. save as last resp
  1262.         CALL    ZCPUTC            ; .. tell remote .. no go
  1263.         CALL    ZCCLRCOM            ; .. clear our recv buffer
  1264.         INC     ERRORS            ; increment error count
  1265.         STC                 ; show error condition
  1266.         JMP     SHORT ZCBLKRCV90        ; .. and return to caller
  1267. ZCBLKRCV80: MOV     AL, ACK            ; al = ACK
  1268.         MOV     LAST_RESP, AL        ; .. save as last resp
  1269.         CALL    ZCPUTC            ; .. tell remote .. all is go
  1270.         INC     RCV_BLKNO            ; next block number
  1271.         MOV     AL, [SI+MCMD]        ; al = received command
  1272.         CMP     AL, DIENOW            ; Q. die now?
  1273.         JNE     ZCBLKRCV85            ; A. no .. continue
  1274.         MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> shutdown msg
  1275.         CALL    ZCDIE            ; .. end it all now
  1276. ZCBLKRCV85: CLC                 ; show received ok
  1277. ZCBLKRCV90: POP     SI                ; restore regs
  1278.         POP     DI                ; save regs
  1279.         POP     DX
  1280.         POP     CX
  1281.         POP     BX
  1282.         RET
  1283. ZCBLKRCV    ENDP
  1284. ; ---------------------------------------------------------------------
  1285. ; Determine if chars are available.  If so, attempt to receive a block.
  1286. ; Exit: CY=block not available; NC=block received ok, in wbuf, starting w/CRC.
  1287. ;    al = command byte
  1288. ; ---------------------------------------------------------------------
  1289. ZCTRYRCV    PROC    NEAR
  1290.         CALL    ZCGETC            ; Q. any chars available?
  1291.         JC        ZCTRYRCV90            ; A. no .. exit
  1292.         CMP     AL, STX            ; Q. stx received?
  1293.         JNE     ZCTRYRCV60            ; A. no .. exit
  1294.         CALL    ZCBLKRCV            ; receive a block
  1295.         JMP     SHORT ZCTRYRCV90        ; tell 'em how it went
  1296. ZCTRYRCV60: CMP     AL, RLR            ; Q. request of last resp?
  1297.         JNE     ZCTRYRCV70            ; A. no .. show no block
  1298.         MOV     AL, NAK            ; al = resend last block
  1299.         CALL    ZCPUTC            ; .. send the response
  1300. ZCTRYRCV70: STC                 ; show no block
  1301. ZCTRYRCV90: RET                 ; .. and exit
  1302. ZCTRYRCV    ENDP
  1303. ; ---------------------------------------------------------------------
  1304. ; This routine subtracts the IO_LEN from the bytes in the current file, and
  1305. ; prints the number of blocks left to transfer on each 10h blocks transferred
  1306. ; ---------------------------------------------------------------------
  1307. ZCPRTLFT    PROC    NEAR
  1308.         PUSH    AX                ; save regs
  1309.         PUSH    CX
  1310.         CMP     WORD PTR BYTESLFT+2, 0    ; Q. < 64k bytes to go?
  1311.         JA        ZCPRTLFT10            ; A. no .. continue
  1312.         CMP     WORD PTR BYTESLFT, IO_LEN    ; Q. io_len left?
  1313.         JA        ZCPRTLFT10            ; A. yes .. continue
  1314.         MOV     WORD PTR BYTESLFT, 0    ; zero out bytes left
  1315.         JMP     SHORT ZCPRTLFT80        ; ... and print!
  1316. ZCPRTLFT10: SUB     WORD PTR BYTESLFT, IO_LEN    ; subtract transferred
  1317.         SBB     WORD PTR BYTESLFT+2, 0    ; .. from left to xfer
  1318.         MOV     AX, WORD PTR BYTESLFT    ; get # bytes left (lws)
  1319.         AND     AX, 1E00H            ; Q. 16 block boundary?
  1320.         JNZ     ZCPRTLFT90            ; A. no .. skip print
  1321. ZCPRTLFT80: CALL    ZCPRBLKS            ; .. print # blocks left
  1322. ZCPRTLFT90: POP     CX                ; restore regs
  1323.         POP     AX
  1324.         RET                 ; .. return to caller
  1325. ZCPRTLFT    ENDP
  1326. ; ---------------------------------------------------------------------
  1327. ; This routine calculates and prints the number of blocks left.
  1328. ; ---------------------------------------------------------------------
  1329. ZCPRBLKS    PROC    NEAR
  1330.         PUSH    AX                ; restore es
  1331.         PUSH    BX
  1332.         PUSH    CX
  1333.         PUSH    DX
  1334.         PUSH    DI
  1335.         PUSH    ES                ; save es
  1336.         LES     BX, BYTESLFT        ; bx = bytes left
  1337.         MOV     DX, ES            ; dx = high order
  1338.         POP     ES                ; .. restore es
  1339.         CLC                 ; clear the carry bit
  1340.         RCR     DX, 1            ; move lsb of dx to cf
  1341.         RCR     BX, 1            ; .. continue in bx
  1342.         MOV     BL, BH            ; bl = low order
  1343.         MOV     BH, DL            ; bh = middle
  1344.         MOV     DL, DH            ; dl = hight
  1345.         XOR     DH, DH            ; .. high is zero
  1346.         MOV     DI, OFFSET B_LEFT        ; di -> blocks left
  1347.         STD                 ; .. and count down
  1348.         MOV     CX, 6            ; .. max bytes to do
  1349. ZCPRBLKS20: PUSH    CX                ; save counter
  1350.         MOV     AL, BL            ; al = digit
  1351.         AND     AL, 0FH            ; .. upper bits off
  1352.         OR        AL, 30H            ; change to printable
  1353.         CMP     AL, '9'                 ; Q. above '9'?
  1354.         JNA     ZCPRBLKS25            ; A. no .. continue
  1355.         ADD     AL, 7            ; .. convert to prtable
  1356. ZCPRBLKS25: STOSB                ; save the char
  1357.         MOV     CL, 4            ; cl = shift value
  1358. ZCPRBLKS27: CLC                 ; clear the carry bit
  1359.         RCR     DX, 1            ; rotate dx:bs ..
  1360.         RCR     BX, 1            ; .. by as many bits as needed
  1361.         LOOP    ZCPRBLKS27            ; .. continue
  1362.         POP     CX                ; .. restore count
  1363.         OR        BX, BX            ; Q. all done?
  1364.         JNZ     ZCPRBLKS30            ; A. no .. continue
  1365.         OR        DX, DX            ; Q. all done?
  1366.         JZ        ZCPRBLKS40            ; A. yes .. print it
  1367. ZCPRBLKS30: LOOP    ZCPRBLKS20            ; .. xlat next char
  1368. ZCPRBLKS40: LEA     DX, [DI+1]            ; dx -> message to print
  1369.         MOV     AH, 9            ; .. ah = print ascii$
  1370.         INT     21H             ; .. ask DOS to do it
  1371.         CLD                 ; .. return direction to up
  1372.         POP     DI                ; restore registers
  1373.         POP     DX
  1374.         POP     CX
  1375.         POP     BX
  1376.         POP     AX
  1377.         RET
  1378. ZCPRBLKS    ENDP
  1379. ; ---------------------------------------------------------------------
  1380. ; Determine if speed sync string received ok.
  1381. ; Entry: Receive buffer should have sync string.
  1382. ; Exit: Carry bit set indicates sync error.
  1383. ; ---------------------------------------------------------------------
  1384. ZCSPDCHK    PROC    NEAR
  1385.         CALL    ZCLSRGET            ; Q. did lsr change?
  1386.         JNC     ZCSPDCHK10            ; A. no .. check received string
  1387.         AND     AL, LSR_ERR         ; Q. any error?
  1388.         JNZ     ZCSPDCHK90            ; A. yes .. return.
  1389. ZCSPDCHK10: MOV     CX, SYNC_LEN        ; len of speed set
  1390.         MOV     BL, 0            ; start of speed string
  1391. ZCSPDCHK20: MOV     AX, WAIT_COUNT        ; ax = wait counter
  1392.         ADD     AX, 2            ; .. wait 2 ticks, max
  1393. ZCSPDCHK25: CALL    ZCGETC            ; Q. any char?
  1394.         JNC     ZCSPDCHK30            ; A. yes ... check it
  1395.         CMP     WAIT_COUNT, AX        ; Q. count up?
  1396.         JB        ZCSPDCHK25            ; A. no .. check again.
  1397.         JMP     SHORT ZCSPDCHK90        ; .. else .. error
  1398. ZCSPDCHK30: CMP     AL, BL            ; Q. same character?
  1399.         JNE     ZCSPDCHK90            ; A. no .. error
  1400.         ADD     BL, SYNC_INC        ; bl = next char
  1401.         LOOP    ZCSPDCHK20            ; .. check next char
  1402.         CLC                 ; show sync ok
  1403.         RET                 ; .. return to caller
  1404. ZCSPDCHK90: STC                 ; show no sync
  1405.         RET                 ; .. return to caller
  1406. ZCSPDCHK    ENDP
  1407. ; ---------------------------------------------------------------------
  1408. ; This routine causes a prompt to be placed on both machines.
  1409. ; The response may be given from either machine.
  1410. ; Entry: di -> prompt message, ended in $
  1411. ; Exit: al = response
  1412. ; ---------------------------------------------------------------------
  1413. ZCSPROMPT   PROC    NEAR
  1414.         PUSH    BX                ; save registers
  1415.         PUSH    CX
  1416.         PUSH    DX
  1417.         PUSH    SI
  1418.         PUSH    DI
  1419.         CLD                 ; clear direction
  1420.         PUSH    DI                ; save initial pointer
  1421.         MOV     AL, '$'                 ; Look for $ character
  1422.         MOV     CX, 100            ; .. max 100 chars
  1423.    REPNE    SCASB                ; .. find the value
  1424.         MOV     CX, DI            ; cx -> char after '$'
  1425.         POP     SI                ; si -> start of string
  1426.         SUB     CX, SI            ; cx = length of string
  1427.         MOV     AL, OPR_PROMPT        ; al = command (prompt)
  1428.         CALL    ZCBLKSND            ; Q. send ok?
  1429.         MOV     DX, SI            ; bx -> start of string
  1430.         CALL    ZCPRESP            ; prompt & get response
  1431.         POP     DI                ; restore regs
  1432.         POP     SI
  1433.         POP     DX
  1434.         POP     CX
  1435.         POP     BX
  1436.         RET
  1437. ZCSPROMPT   ENDP
  1438. ; ---------------------------------------------------------------------
  1439. ; This routine displays a prompt and waits for a response.
  1440. ; The response may be given from either machine.
  1441. ; Entry: dx -> prompt message, ended in $
  1442. ; Exit: al = response; Carry=response came from remote machine
  1443. ;    no carry - response came from local machine
  1444. ; ---------------------------------------------------------------------
  1445. ZCPRESP     PROC    NEAR
  1446.         PUSH    SI                ; save regs
  1447.         PUSH    BX
  1448.         PUSH    CX
  1449.         MOV     AH, 09H            ; al = print string
  1450.         INT     21H             ; .. display prompt
  1451.         MOV     BX, WBUF            ; bx -> wbuf
  1452. ZCPRESP10:  CALL    ZCTIMUP            ; update timer
  1453.         MOV     AH, 1            ; ah = query keyboard
  1454.         INT     16H             ; Q. is a key available?
  1455.         JZ        ZCPRESP20            ; A. no .. check for block
  1456.         MOV     AH, 0            ; al = get key
  1457.         INT     16H             ; al = key typed
  1458.         PUSH    AX                ; save ax
  1459.         MOV     [BX], AL            ; save response in wbuf
  1460.         MOV     AL, OPR_REPLY        ; al = command
  1461.         MOV     SI, WBUF            ; si -> wbuf
  1462.         MOV     CX, 1            ; cx = # chars to send
  1463.         CALL    ZCBLKSND            ; send the block
  1464.         POP     AX                ; restore reply
  1465.         CLC                 ; response from local
  1466.         JMP     SHORT ZCPRESP90        ; .. return to caller
  1467. ZCPRESP20:  CALL    ZCTRYRCV            ; Q. block available?
  1468.         JC        ZCPRESP10            ; A. no .. try again
  1469.         CMP     BYTE PTR [BX+MCMD], OPR_REPLY   ; Q. reply?
  1470.         JNE     ZCPRESP10                ; A. no .. try again
  1471.         MOV     AL, BYTE PTR [BX+MDATA] ; al = response
  1472.         STC                 ; response from remote
  1473. ZCPRESP90:  POP     CX                ; restore regs
  1474.         POP     BX
  1475.         POP     SI
  1476.         RET                 ; return to caller
  1477. ZCPRESP     ENDP
  1478. ; ---------------------------------------------------------------------
  1479. ; This routine displays the prompt sent from the other machine.
  1480. ; Entry: wbuf contains received prompt
  1481. ; ---------------------------------------------------------------------
  1482. ZCPPROMPT   PROC    NEAR
  1483.         PUSH    AX                ; save ax
  1484.         MOV     DX, WBUF            ; dx -> received buffer
  1485.         ADD     DX, MDATA            ; dx -> prompt
  1486.         CALL    ZCPRESP            ; get response
  1487.         POP     AX                ; restore ax
  1488.         RET                 ; return to caller
  1489. ZCPPROMPT   ENDP
  1490. ; ---------------------------------------------------------------------
  1491. ; This routine sends the requested file.
  1492. ; Entry: handle = currently opened file.
  1493. ; ---------------------------------------------------------------------
  1494. ZCSEND        PROC    NEAR
  1495.         PUSH    AX                ; save regs
  1496.         PUSH    BX
  1497.         PUSH    CX
  1498.         PUSH    DX
  1499.         PUSH    SI
  1500.         MOV     AL, CRE_FILE        ; al = file header cmd
  1501.         MOV     CX, DTA_LEN         ; cx = find file data
  1502.         MOV     SI, DTA            ; si -> dta
  1503.         CALL    ZCBLKSND            ; send the request
  1504.         CALL    ZCRECV            ; get the response
  1505.         CMP     AL, MSG_NAK         ; Q. create ok?
  1506.         JNE     ZCSEND10            ; A. yes .. continue
  1507.         MOV     DX, OFFSET FILENOPEN    ; dx -> error message
  1508.         MOV     AH, 9            ; ah = print ascii$
  1509.         INT     21H             ; .. tell 'em, Jim
  1510.         JMP     SHORT ZCSEND90        ; try next file
  1511. ZCSEND10:   MOV     CX, XBUF_LTS        ; cx = bytes left to send
  1512.         OR        CX, CX            ; Q. any?
  1513.         JNZ     ZCSEND20            ; A. yes .. send them
  1514.         MOV     AH, 3FH            ; ah = read from file
  1515.         MOV     BX, HANDLE            ; .. bx = file handle
  1516.         MOV     CX, XBUF_RBL        ; .. cx = # of bytes
  1517.         MOV     DX, XBUF            ; .. dx -> buffer
  1518.         MOV     XBUF_PTR, DX        ; .. save in send pointer
  1519.         INT     21H             ; .. read a buffer full
  1520.         JC        ZCSEND80            ; .. process errors
  1521.         OR        AX, AX            ; Q. anything read?
  1522.         JZ        ZCSEND70            ; A. no .. eof
  1523.         MOV     CX, AX            ; cx = number of bytes
  1524.         MOV     XBUF_LTS, AX        ; .. left to send
  1525. ZCSEND20:   CMP     CX, IO_LEN            ; Q. more than io_len?
  1526.         JNA     ZCSEND25            ; A. no .. send it
  1527.         MOV     CX, IO_LEN            ; cx = bytes to send
  1528. ZCSEND25:   SUB     XBUF_LTS, CX        ; adjust pointer
  1529.         MOV     SI, XBUF_PTR        ; .. si -> data
  1530.         ADD     XBUF_PTR, CX        ; .. adjust pointer
  1531.         MOV     AL, DATA_BLK        ; .. al = data block cmd
  1532.         MOV     ERRORS, 0            ; .. zero out errors
  1533.         CALL    ZCBLKSND            ; .. send a block
  1534.         CALL    ZCRECV            ; wait & execute reply
  1535.         CALL    ZCPRTLFT            ; .. print blocks left
  1536.         CMP     ERRORS, MAX_ERRORS        ; Q. too many errors
  1537.         JB        ZCSEND10            ; A. no ..continue
  1538.         MOV     AL, RESYNC            ; al = resync
  1539.         MOV     CX, 0            ; cx = no data to send
  1540.         CALL    ZCBLKSND            ; .. send the block
  1541.         CALL    RESYNC_P            ; resync on too many block errs
  1542.         JMP     ZCSEND10            ; .. and continue
  1543. ZCSEND70:   MOV     AL, EOF_MARK        ; al = eof command
  1544.         XOR     CX, CX            ; .. cx = no data
  1545.         CALL    ZCBLKSND            ; .. tell other side
  1546.         CALL    ZCRECV            ; wait for reply
  1547.         JMP     SHORT ZCSEND90        ; .. return to caller
  1548. ZCSEND80:   MOV     AL, SHUTDOWN        ; al = shutdown command
  1549.         XOR     CX, CX            ; .. cx = no data
  1550.         CALL    ZCBLKSND            ; .. tell other side
  1551. ZCSEND90:   POP     SI                ; restore registers
  1552.         POP     DX
  1553.         POP     CX
  1554.         POP     BX
  1555.         POP     AX
  1556.         RET
  1557. ZCSEND        ENDP
  1558. ; ---------------------------------------------------------------------
  1559. ; Receive blocks and process them based on request from the other machine.
  1560. ; ---------------------------------------------------------------------
  1561. ZCRECV        PROC    NEAR
  1562.         MOV     BX, WAIT_COUNT        ; bx = current wait count
  1563.         ADD     BX, SEC_10            ; bx = ten secs from now
  1564. ZCRECV05:   CALL    ZCTIMUP            ; update the timer
  1565.         CMP     WAIT_COUNT, BX        ; Q. 10 seconds yet?
  1566.         JB        ZCRECV07            ; A. no .. continue
  1567.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  1568.         CALL    ZCDIE            ; .. I'm dead, Jim
  1569. ZCRECV07:   CALL    ZCTRYRCV            ; Q. anything waiting?
  1570.         JC        ZCRECV05            ; A. no.. try again
  1571.         CBW                 ; ax = command
  1572.         SHL     AL, 1            ; ax = entry offset
  1573.         LEA     BX, MSG_P_TBL-2        ; bx -> message table
  1574.         ADD     BX, AX            ; bx -> run pointer
  1575.         CALL    [BX]            ; .. call requested routine
  1576. ZCRECV90:   RET                 ; return to caller
  1577. ZCRECV        ENDP
  1578. ; ----------------------------------------
  1579. ; create the requested file
  1580. ; ----------------------------------------
  1581. CRE_FILE_P  PROC    NEAR            ; create file
  1582.         PUSH    AX                ; save regs
  1583.         PUSH    BX
  1584.         PUSH    CX
  1585.         PUSH    SI
  1586.         PUSH    DI
  1587.         MOV     WAIT_COUNT, 0        ; clear the wait counter
  1588.         MOV     SI, WBUF            ; si -> received data
  1589.         MOV     AX, [SI+MDATA+28]        ; ax =  file size high
  1590.         MOV     WORD PTR BYTESLFT+2, AX ; .. save high value
  1591.         MOV     AX, [SI+MDATA+26]        ; ax = file size low
  1592.         MOV     WORD PTR BYTESLFT, AX   ; .. save low value
  1593.         ADD     SI, MDATA+30        ; si -> file name
  1594.         MOV     DI, OFFSET FILENAME     ; di -> file name area
  1595.         MOV     CX, 13            ; .. length to move
  1596.        REP  MOVSB                ; move in the file name
  1597.         MOV     DX, OFFSET CURDIR        ; dx -> file name to open
  1598.         XOR     CX, CX            ; cx = attributes
  1599.         MOV     AH, 3CH            ; ah = create file
  1600.         INT     21H             ; Q. create ok?
  1601.         JC        CRE_FILEP1            ; A. no .. error
  1602.         MOV     HANDLE, AX            ; save handle
  1603.         OR        FLG1, FLG1O         ; .. show file is open
  1604.         MOV     SI, WBUF            ; si -> received data
  1605.         PUSH    MDATA+22[SI]        ; push file time
  1606.         POP     FILETIME            ; .. pop it
  1607.         PUSH    MDATA+24[SI]        ; push file date
  1608.         POP     FILEDATE            ; .. pop it
  1609.         MOV     SI, OFFSET FILENAME     ; si -> file created
  1610.         CALL    ZCPRTAZ            ; .. print the name
  1611.         MOV     DX, OFFSET BRECVD        ; dx -> being received
  1612.         MOV     AH, 09H            ; ah = print ascii$ string
  1613.         INT     21H             ; .. print the string
  1614.         CALL    ZCPRBLKS            ; .. print blocks to send
  1615.         MOV     AL, MSG_ACK         ; ack the request
  1616.         JMP     SHORT CRE_FILEP2        ; .. continue
  1617. CRE_FILEP1: MOV     AH, 9            ; ah = print ascii$
  1618.         MOV     DX, OFFSET FILENOPEN    ; dx -> error message
  1619.         INT     21H             ; .. tell 'em Jim
  1620.         MOV     AL, MSG_NAK         ; nak the request
  1621. CRE_FILEP2: MOV     CX, 0            ; .. no data
  1622.         CALL    ZCBLKSND            ; .. reply
  1623.         POP     DI                ; restore regs
  1624.         POP     SI
  1625.         POP     CX
  1626.         POP     BX
  1627.         POP     AX
  1628.         RET
  1629. CRE_FILE_P  ENDP
  1630. ; ----------------------------------------
  1631. ; determine if file exists
  1632. ; ----------------------------------------
  1633. QRY_FLE_P   PROC    NEAR            ; determine if file exists
  1634.         PUSH    AX                ; save caller's regs
  1635.         PUSH    CX
  1636.         PUSH    DX
  1637.         PUSH    SI
  1638.         PUSH    DI
  1639.         MOV     SI, WBUF            ; si -> received data
  1640.         ADD     SI, MDATA+30        ; si -> file name
  1641.         MOV     DI, OFFSET FILENAME     ; di -> file name area
  1642.         MOV     CX, 13            ; .. length to move
  1643.        REP  MOVSB                ; move in the file name
  1644.         MOV     DX, OFFSET CURDIR        ; dx -> file name to open
  1645.         XOR     CX, CX            ; cx = attributes
  1646.         MOV     AH, 4EH            ; ah = find first
  1647.         INT     21H             ; Q. file found?
  1648.         JC        QRY_FLE_P1            ; A. no .. error
  1649.         MOV     AL, MSG_ACK         ; ack the request
  1650.         JMP     SHORT QRY_FLE_P2        ; .. continue
  1651. QRY_FLE_P1: MOV     AL, MSG_NAK         ; nak the request
  1652. QRY_FLE_P2: PUSH    AX                ; save reply
  1653.         MOV     AH, 36H            ; ah = get free space
  1654.         XOR     DL, DL            ; .. on current drive
  1655.         INT     21H             ; .. via dos
  1656.         XOR     DX, DX            ; dx = 0
  1657.         MUL     CX                ; .. clusters x secs/cluster
  1658.         MUL     BX                ; .. secs x bytes/sector
  1659.         MOV     DS:DTA+DTA_LEN, AX        ; save lsw of free
  1660.         MOV     DS:DTA+DTA_LEN+2, DX    ; .. and msw
  1661.         MOV     CX, DTA_LEN+4        ; cx = find file data len
  1662.         MOV     SI, DTA            ; si -> dta
  1663.         POP     AX                ; .. restore reply
  1664.         CALL    ZCBLKSND            ; .. send reply
  1665.         POP     DI                ; restore caller's regs
  1666.         POP     SI
  1667.         POP     DX
  1668.         POP     CX
  1669.         POP     AX
  1670.         RET
  1671. QRY_FLE_P   ENDP
  1672. ; ----------------------------------------
  1673. ; process shutdown request
  1674. ; ----------------------------------------
  1675. SHUTDOWN_P  PROC    NEAR            ; process shutdown request
  1676.         MOV     DX, OFFSET SHUTDOWN_R   ; dx -> request
  1677.         JMP     ZCDIE            ; .. we'll never return
  1678. SHUTDOWN_P  ENDP
  1679. ; ----------------------------------------
  1680. ; ack received
  1681. ; ----------------------------------------
  1682. MSG_ACK_P   PROC    NEAR            ; process ack
  1683.         CLC                 ; show ack received
  1684.         RET
  1685. MSG_ACK_P   ENDP
  1686. ; ----------------------------------------
  1687. ; process nak request
  1688. ; ----------------------------------------
  1689. MSG_NAK_P   PROC    NEAR            ; process nak
  1690.         STC                 ; show nak received
  1691.         RET
  1692. MSG_NAK_P   ENDP
  1693. ; ----------------------------------------
  1694. ; process data block
  1695. ; ----------------------------------------
  1696. DATA_BLK_P  PROC    NEAR            ; process data block
  1697.         MOV     BX, WBUF            ; bx -> buffer
  1698.         LEA     DX, [BX+MDATA]        ; dx -> data area
  1699.         MOV     DI, XBUF_PTR        ; di -> build buffer
  1700.         MOV     SI, DX            ; si -> input data
  1701.         MOV     CX, [BX+MLEN]        ; cx = buffer length
  1702.         SUB     CX, 3            ; .. exclude cmd & blkno
  1703.         CLD                 ; .. positive direction
  1704.      REP    MOVSB                ; .. move data to buffer
  1705.         MOV     XBUF_PTR, DI        ; save new o/p ptr
  1706.         MOV     SI, XBUF            ; si -> xbuf
  1707.         ADD     SI, XBUF_WL         ; si -> write pos
  1708.         CMP     DI, SI            ; Q. write?
  1709.         JB        DATA_BLK90            ; A. no .. continue
  1710.         MOV     CX, XBUF_PTR        ; cx -> past data
  1711.         MOV     DX, XBUF            ; dx -> data
  1712.         SUB     CX, DX            ; cx = data length
  1713.         MOV     XBUF_PTR, DX        ; .. save put pointer
  1714.         MOV     BX, HANDLE            ; bx - handle
  1715.         MOV     AH, 40H            ; ah = write
  1716.         INT     21H             ; .. write file
  1717. DATA_BLK90: CALL    ZCPRTLFT            ; print # blocks left
  1718.         MOV     AL, MSG_ACK         ; ack the msg
  1719.         XOR     CX, CX            ; .. no data
  1720.         CALL    ZCBLKSND            ; .. send it
  1721.         RET
  1722. DATA_BLK_P  ENDP
  1723. ; ----------------------------------------
  1724. ; process eof request
  1725. ; ----------------------------------------
  1726. EOF_MARK_P  PROC    NEAR            ; process eof
  1727.         MOV     CX, XBUF_PTR        ; cx -> past data
  1728.         MOV     DX, XBUF            ; dx -> data
  1729.         SUB     CX, DX            ; Q. any to write?
  1730.         JZ        EOF_MARK80            ; A. no .. close & exit
  1731.         MOV     XBUF_PTR, DX        ; .. save put pointer
  1732.         MOV     BX, HANDLE            ; bx - handle
  1733.         MOV     AH, 40H            ; ah = write
  1734.         INT     21H             ; .. write file
  1735. EOF_MARK80: MOV     BX, HANDLE            ; bx = handle to close
  1736.         TEST    FLG, FLGD            ; Q. use machine date?
  1737.         JNZ     EOF_MARK85            ; A. yes .. skip sent date.
  1738.         MOV     AX, 5701H            ; ax = set file date
  1739.         MOV     CX, FILETIME        ; cx = file time
  1740.         MOV     DX, FILEDATE        ; dx = file date
  1741.         INT     21H             ; set file date & time
  1742. EOF_MARK85: MOV     AH, 3EH            ; ah = close command
  1743.         INT     21H             ; .. close the file
  1744.         AND     FLG1, NOT FLG1O        ; .. show file closed
  1745.         MOV     AL, MSG_ACK         ; ack the msg
  1746.         XOR     CX, CX            ; .. no data
  1747.         CALL    ZCBLKSND            ; .. send it
  1748.         MOV     DX, OFFSET CRLF        ; dx -> crlf
  1749.         MOV     AH, 9            ; ah = print ascii$
  1750.         INT     21H             ; .. display it
  1751.         RET
  1752. EOF_MARK_P  ENDP
  1753. ; ----------------------------------------
  1754. ; process set flags request
  1755. ; ----------------------------------------
  1756. SET_FLG_P   PROC    NEAR            ; process verify ok
  1757.         MOV     BX, WBUF            ; bx -> received packet
  1758.         MOV     AL, MDATA[BX]        ; al = flags sent
  1759.         AND     AL, FLG_SET         ; assure other flags off
  1760.         OR        FLG, AL            ; .. turn on other flags
  1761.         MOV     AL, FLG            ; al = new flag set
  1762.         AND     AL, FLG_SET         ; .. set off others
  1763.         XOR     CX, CX            ; cx = send no data
  1764.         CALL    ZCBLKSND            ; .. return flags
  1765.         RET
  1766. SET_FLG_P   ENDP
  1767. ; ----------------------------------------
  1768. ; resync speed
  1769. ; ----------------------------------------
  1770. RESYNC_P    PROC    NEAR            ; resync speed
  1771.         MOV     DX, OFFSET TOOMANY        ; dx -> message
  1772.         MOV     AH, 9            ; ah = print ascii$
  1773.         INT     21H             ; .. display message
  1774.         MOV     DSRWAIT, SEC_30        ; .. reset start wait time
  1775.         CMP     FLGPCR,0                ; Q. pcremote active
  1776.         JZ      RESYNC_P10              ; A. no
  1777.         JMP     RESYNC_P20              ; A. yes, don't change baud rate
  1778. RESYNC_P10: INC     BAUD_CNTR            ; .. select next baud rate
  1779. RESYNC_P20: CALL    ZCSPEED            ; .. resync
  1780.         CALL    ZCCLRCOM            ; .. clear our recv buffer
  1781.         RET
  1782. RESYNC_P    ENDP
  1783. ; ---------------------------------------------------------------------
  1784. ; This routine will send the requested files.
  1785. ; Exit: Returns to DOS when all files sent.
  1786. ; ---------------------------------------------------------------------
  1787. ZCSF        PROC    NEAR
  1788.         MOV     AH, FNDOP            ; ah = find operation to use
  1789.         XOR     CX, CX            ; cx = attribute to find
  1790.         MOV     DX, OFFSET CURDIR        ; dx -> path/filename
  1791.         INT     21H             ; Q. any file found?
  1792.         JNC     ZCSF05            ; A. yes .. try to send it
  1793.         JMP     ZCSF90            ; .. else .. end of job
  1794. ZCSF05:     MOV     FNDOP, 4FH            ; set op to find next
  1795.         PUSH    ES                ; save es
  1796.         LES     AX, DS:DWORD PTR DTA_LSIZ    ; es:ax = file size
  1797.         MOV     WORD PTR BYTESLFT, AX    ; .. save lsw
  1798.         MOV     WORD PTR BYTESLFT+2, ES    ; .. and msw
  1799.         POP     ES
  1800.         MOV     AX, 3D00H            ; ax = open for read
  1801.         MOV     DX, DTA_NAME        ; ds:dx -> filename to open
  1802.         INT     21H             ; Q. open the file ok?
  1803.         JC        ZCSF            ; A. no .. try next file
  1804.         MOV     HANDLE, AX            ; save the handle
  1805.         MOV     AL, QRY_FLE         ; al = determine existence
  1806.         MOV     CX, DTA_LEN         ; cx = find file data
  1807.         MOV     SI, DTA            ; si -> dta
  1808.         CALL    ZCBLKSND            ; send the request
  1809.         CALL    ZCRECV            ; Q. does file exist?
  1810.         MOV     BX, WBUF            ; bx -> received buffer
  1811.         MOV     AX,WORD PTR DTA_LEN[BX+MDATA]   ; ax = lsw of free
  1812.         MOV     DX,WORD PTR DTA_LEN[BX+2+MDATA] ; dx = msw of free
  1813.         MOV     FILESZL, AX         ; .. save locally
  1814.         MOV     FILESZH, DX         ; .. lsw & msw
  1815.         JC        ZCSF20            ; A. no .. continue
  1816.         ADD     AX, MDATA+26[BX]        ; add in file's len
  1817.         ADC     DX, MDATA+28[BX]        ; .. lsw & msw
  1818.         MOV     FILESZL, AX         ; .. save locally
  1819.         MOV     FILESZH, DX         ; .. lsw & msw
  1820.         TEST    FLG, FLGO            ; Q. overwrite?
  1821.         JNZ     ZCSF20            ; A. yes .. make it so
  1822.         TEST    FLG, FLGU            ; Q. update?
  1823.         JZ        ZCSF10            ; A. no .. ask operator
  1824.         MOV     BX, WBUF            ; bx -> recv'd message
  1825.         MOV     AX, MDATA+24[BX]        ; ax = receiver's file date
  1826.         CMP     AX, DS:DTA_DATE        ; Q. is receivers file older?
  1827.         JB        ZCSF20            ; A. yes..    send our's
  1828.         JA        ZCSF80            ; A. younger .. skip it
  1829.         MOV     AX, MDATA+22[BX]        ; ax = receiver's file time
  1830.         CMP     AX, DS:DTA_TIME        ; Q. is receivers file older?
  1831.         JB        ZCSF20            ; A. yes .. send our's
  1832.         JMP     SHORT ZCSF80        ; .. else .. skip
  1833. ZCSF10:     MOV     DX, OFFSET FILEXISTS    ; dx -> message
  1834.         CALL    ZCFPR            ; .. issue overwrite prompt
  1835.         CMP     AL, 'Y'                 ; Q. overwrite?
  1836.         JE        ZCSF20            ; A. yes .. do it
  1837.         CMP     AL, 'N'                 ; Q. do not overwrite?
  1838.         JE        ZCSF80            ; A. yes ... skip file
  1839.         JMP     SHORT ZCSF10        ; .. retry prompt
  1840. ZCSF20:     MOV     AX, DS:DTA_HSIZ        ; ax = hi file size
  1841.         CMP     AX, FILESZH         ; Q. is our file smaller?
  1842.         JB        ZCSF30            ; A. yes .. start transfer
  1843.         JA        ZCSF25            ; A. no .. check for abort
  1844.         MOV     AX, DS:DTA_LSIZ        ; .. get low order
  1845.         CMP     AX, FILESZL         ; Q. is our file smaller?
  1846.         JNA     ZCSF30            ; A. yes .. start transfer
  1847. ZCSF25:     TEST    FLG, FLGA            ; Q. abort if too big?
  1848.         JNZ     ZCSF28            ; A. no .. next file
  1849.         MOV     SI, DTA_NAME        ; si -> file name
  1850.         CALL    ZCPRTAZ            ; .. display it
  1851.         MOV     DX, OFFSET TOOBIG        ; dx -> too big message
  1852.         MOV     AH, 9            ; ah = print to $
  1853.         INT     21H             ; .. display message
  1854.         JMP     SHORT ZCSF80        ; .. next file
  1855. ZCSF28:     MOV     DI, OFFSET DISKFULL     ; di -> full prompt
  1856.         CALL    ZCSPROMPT            ; .. tell the user
  1857.         JMP     SHORT ZCSF90        ; .. shutdown
  1858. ZCSF30:     MOV     SI, DTA_NAME        ; si -> filename
  1859.         CALL    ZCPRTAZ            ; print the
  1860.         MOV     DX, OFFSET BSENT        ; dx -> being sent
  1861.         MOV     AH, 09H            ; ah = display ascii$
  1862.         INT     21H             ; display message
  1863.         CALL    ZCPRBLKS            ; print blocks left message
  1864.         MOV     WAIT_COUNT, 0        ; .. clear the wait count value
  1865.         CALL    ZCSEND            ; .. and send the file
  1866.         MOV     DX, OFFSET CRLF        ; dx -> crlf
  1867.         MOV     AH, 9            ; ah = print ascii$
  1868.         INT     21H             ; .. display it
  1869. ZCSF80:     MOV     BX, HANDLE            ; bx = handle of last file
  1870.         MOV     AH, 3EH            ; ah = close file opcode
  1871.         INT     21H             ; .. file closed, captain!
  1872.         JMP     ZCSF            ; .. try next file
  1873. ZCSF90:     MOV     AL, SHUTDOWN        ; al = shutdown command
  1874.         XOR     CX, CX            ; .. no data is sent
  1875.         CALL    ZCBLKSND            ; send the command
  1876.         MOV     DX, OFFSET SHUTDOWN_R   ; dx -> shutdown string
  1877.         JMP     ZCDIE            ; end gracefully
  1878. ZCSF        ENDP
  1879. ; ---------------------------------------------------------------------
  1880. ; This routine will display the requested string.
  1881. ; Entry: si -> string to print.
  1882. ; ---------------------------------------------------------------------
  1883. ZCPRTAZ     PROC    NEAR
  1884.         PUSH    AX                ; save regs
  1885.         PUSH    DX
  1886.         PUSH    SI
  1887.         MOV     AH, 02H            ; ah = display character
  1888. ZCPRTAZ10:  LODSB                ; al = char to prt
  1889.         OR        AL, AL            ; Q. anything to prt?
  1890.         JZ        ZCPRTAZ90            ; A. no .. return
  1891.         MOV     DL, AL            ; dl = char to prt
  1892.         INT     21H             ; .. display the char
  1893.         JMP     ZCPRTAZ10            ; .. next char
  1894. ZCPRTAZ90:  POP     SI                ; restore regs
  1895.         POP     DX
  1896.         POP     AX
  1897.         RET                 ; return to caller
  1898. ZCPRTAZ     ENDP
  1899. ; ---------------------------------------------------------------------
  1900. ; This routine will build a prompt for both machines.
  1901. ; Entry: filename in the DTA contains file name; dx -> prompt string to use
  1902. ; Exit: al = reply char, upper case
  1903. ; ---------------------------------------------------------------------
  1904. ZCFPR        PROC    NEAR
  1905.         PUSH    SI                ; save regs
  1906.         PUSH    DI
  1907.         MOV     DI, XBUF            ; di -> work area
  1908.         MOV     SI, DTA_NAME        ; si -> filename
  1909. ZCFPR10:    LODSB                ; al = char from filename
  1910.         OR        AL, AL            ; Q. end of name?
  1911.         JZ        ZCFPR20            ; A. yes .. next field
  1912.         STOSB                ; .. save in xbuf
  1913.         JMP     SHORT ZCFPR10        ; process next char
  1914. ZCFPR20:    MOV     SI, DX            ; dx -> prompt
  1915. ZCFPR25:    LODSB                ; al = prompt char
  1916.         STOSB                ; .. save it
  1917.         CMP     AL, '$'                 ; Q. end of prompt?
  1918.         JNE     ZCFPR25            ; A. no .. continue
  1919.         MOV     DI, XBUF            ; di -> xbuf
  1920.         CALL    ZCSPROMPT            ; issue prompt
  1921.         AND     AL, NOT 20H         ; response to upper case
  1922.         POP     DI                ; restore regs
  1923.         POP     SI
  1924.         RET                 ; return to caller
  1925. ZCFPR        ENDP
  1926. ; ---------------------------------------------------------------------
  1927. ; This routine transfers ZCOPY out the port in DX.
  1928. ; Entry: dx = port to transfer on; cx = # chars to send
  1929. ; Exit: Stops via int 3 - debug better be there
  1930. ; ---------------------------------------------------------------------
  1931. ZCXFER        PROC    NEAR
  1932.         MOV     SI, 0FEH            ; si -> start of area to send
  1933.         MOV     WORD PTR [SI], CX        ; set up length of program
  1934.         ADD     CX, 2            ; add in length
  1935. ZCXFER10:   ADD     DX, 5            ; dx -> lsr
  1936.         IN        AL, DX            ; al = lsr
  1937.         SUB     DX, 5            ; dx -> base port
  1938.         TEST    AL, LSR_THRE        ; Q. thr empty?
  1939.         JZ        ZCXFER10            ; A. no .. wait
  1940.         LODSB                ; al = char to send
  1941.         OUT     DX, AL            ; .. sent the char
  1942.         LOOP    ZCXFER10            ; .. loop til done
  1943.         INT     3                ; then return to debug
  1944. ZCXFER        ENDP
  1945. ;   Uninitialized data areas
  1946. UDATA        EQU     $                ; start of unitialized data
  1947. IO_BASE     EQU     WORD PTR UDATA        ; base com port address
  1948. INT_VECTOR  EQU     BYTE PTR IO_BASE+2        ; interrupt vector to use
  1949. OLD_COM     EQU     DWORD PTR INT_VECTOR+1  ; old interrupt for com:
  1950. OLD_TIMER   EQU     DWORD PTR OLD_COM+4     ; old interrupt for timer tick
  1951. OLD_CTLBRK  EQU     DWORD PTR OLD_TIMER+4   ; old interrupt for control break
  1952. OLD_DOSCTLB EQU     DWORD PTR OLD_CTLBRK+4  ; old interrupt for dos ^break
  1953. OLD_DOSERR  EQU     DWORD PTR OLD_DOSCTLB+4 ; old interrupt for dos error
  1954. HANDLE        EQU     WORD PTR OLD_DOSERR+4   ; open file handle
  1955. RBUF_GPTR   EQU     WORD PTR HANDLE+2        ; receive buffer next get address
  1956. RBUFL        EQU     1100H            ; length of receive buffer
  1957. SBUF        EQU     WORD PTR RBUF_GPTR+2    ; send buffer address
  1958. SBUFL        EQU     600H            ; length of send buffer
  1959. WBUF        EQU     WORD PTR SBUF+2        ; work buffer address
  1960. WBUFL        EQU     500H            ; length of work buffer
  1961. XBUF        EQU     WORD PTR WBUF+2        ; file build buffer
  1962. XBUF_PTR    EQU     WORD PTR XBUF+2        ; i/o pointer
  1963. EDRV        EQU     BYTE PTR XBUF_PTR+2     ; entry time logged drive
  1964. EDIR        EQU     WORD PTR EDRV+1        ; pointer to entry time directory
  1965. EDIRL        EQU     65                ; length of area
  1966. FILESZL     EQU     WORD PTR EDIR+2        ; file size low
  1967. FILESZH     EQU     WORD PTR FILESZL+2        ; .. and high
  1968. FILEDATE    EQU     WORD PTR FILESZH+2        ; file date
  1969. FILETIME    EQU     WORD PTR FILEDATE+2     ; file time
  1970. BYTESLFT    EQU     DWORD PTR FILETIME+2    ; bytes left to transfer
  1971. BUF_START   EQU     BYTESLFT+4            ; start of buffer space
  1972.  
  1973. CSEG        ENDS
  1974.         END     START
  1975.